# Gateway on Azure Container App

<figure><img src="https://762006384-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MJXOXEifAmpyvNVL1to%2Fuploads%2FETnLSTu5qYNj0xwMltI2%2FKeeperPAM%20Machine.jpg?alt=media&#x26;token=7f69333a-8f02-410f-8542-1882216994b6" alt=""><figcaption></figcaption></figure>

## Overview <a href="#overview" id="overview"></a>

This document contains information on how to install, configure, and update your Keeper Gateway on an Azure Container App. The Keeper Gateway container is built upon the base image of Rocky Linux 9 and it is hosted in [DockerHub](https://hub.docker.com/r/keeper/gateway).

## Prerequisites

#### Azure Environment Requirements

* An active Azure Subscription.
* Azure CLI with the `containerapp` extension.
* A Gateway Configuration string from the Keeper Vault.
* A `keyvault` extension if using option B.
* A subnet (minimum `/27`) for the ACA environment, delegated to `Microsoft.App/environments`

#### **Docker Hub Authentication**

To avoid anonymous pull rate limits in Azure (which often result in `429 Too Many Requests` ), you must have:

* **Docker Hub Account:** A registered account at [hub.docker.com](https://hub.docker.com/).
* **Personal Access Token:** A Token generated via **Account Settings > Security** with `Read Only` permissions

<figure><img src="https://762006384-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MJXOXEifAmpyvNVL1to%2Fuploads%2FzFod26aaYPanbWaiQqzH%2FDocker%20PAT.png?alt=media&#x26;token=b550a109-cdd4-48ca-9dab-9e0bf95aaca1" alt=""><figcaption></figcaption></figure>

***

## Create a Gateway <a href="#create-a-gateway" id="create-a-gateway"></a>

A new Gateway deployment can be created by clicking on **Create New** > **Gateway** from the Web Vault or Desktop App.

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

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

The Application names and UIDs can be found with `secrets-manager app list`

***

## Environment Setup

The Container App Environment is the secure boundary for your Gateways.

```
az containerapp env create \
--name <ENVIRONMENT_NAME> \
--resource-group <RESOURCE_GROUP> \
--location <LOCATION> \
--infrastructure-subnet-resource-id /subscriptions/<SUBSCRIPTION_ID>/resourceGroups/<VNET_RESOURCE_GROUP>/providers/Microsoft.Network/virtualNetworks/<VNET_NAME>/subnets/<SUBNET_NAME>
```

<figure><img src="https://762006384-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MJXOXEifAmpyvNVL1to%2Fuploads%2F5as210YOOzlov0jqMFkI%2Fenv.png?alt=media&#x26;token=a2b6ebc1-db3f-479a-a7c3-7140f57deb8d" alt=""><figcaption></figcaption></figure>

### Secrets Management Options

Choose one of the following methods to manage your `GATEWAY_CONFIG`.

#### Option A: Internal Managed Secrets

```
az containerapp create \
  --name <APP_NAME> \
  --resource-group <RESOURCE_GROUP> \
  --environment <ENVIRONMENT_NAME> \
  --image keeper/gateway:latest \
  --cpu 2.0 --memory 8Gi \
  --min-replicas 2 \
  --max-replicas 5 \
  --registry-server index.docker.io \
  --registry-username <DOCKER_HUB_USER> \
  --registry-password <DOCKER_HUB_PASSWORD_OR_PAT> \
  --secrets "gateway-config-secret=<YOUR_BASE64_CONFIG>" \
  --env-vars "ACCEPT_EULA=Y" "GATEWAY_CONFIG=secretref:gateway-config-secret"
```

#### Option B: Azure Key Vault

**Store Secret**: Store your config in Key Vault

```
az keyvault secret set --vault-name <VAULT_NAME> --name "DOCKER-TOKEN" --value "<YOUR_DOCKER_HUB_PAT>"
az keyvault secret set --vault-name <VAULT_NAME> --name "GATEWAY-CONFIG" --value "<YOUR_BASE64_CONFIG>"
```

**Deploy with Identity**: Create the app with a system-assigned identity.

```
az containerapp create \
  --name <APP_NAME> \
  --resource-group <RESOURCE_GROUP> \
  --environment <ENVIRONMENT_NAME> \
  --image keeper/gateway:latest \
  --cpu 2.0 --memory 8Gi \
  --system-assigned \
  --registry-server index.docker.io \
  --registry-username <DOCKER_HUB_USER> \
  --registry-password <Enter your Docker PAT, which starts with dckr_pat_...>
  --env-vars "ACCEPT_EULA=Y"
```

<figure><img src="https://762006384-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MJXOXEifAmpyvNVL1to%2Fuploads%2FXc6V4V8v9hkH3P0YwE1s%2Fcreated.png?alt=media&#x26;token=152b56e8-bd4a-4d87-917d-d890aa300a18" alt=""><figcaption></figcaption></figure>

**Grant Access**: Give the app permission to read the secret.

```
PRINCIPAL_ID=$(az containerapp show -n <APP_NAME> -g <RESOURCE_GROUP> --query identity.principalId -o tsv) 
az role assignment create --assignee $PRINCIPAL_ID --role "Key Vault Secrets User" --scope /subscriptions/<SUB_ID>/resourceGroups/providers/Microsoft.KeyVault/vaults/<VAULT_NAME>
```

**Reference Secret**: Link the Key Vault secret to the app.

```
az containerapp secret set -n <APP_NAME> -g <RESOURCE_GROUP> \
--secrets "docker-password-kv=keyvaultref:https://<VAULT_NAME>.vault.azure.net/secrets/DOCKER-TOKEN,identityref:system" \
"gateway-config-kv=keyvaultref:https://<VAULT_NAME>.vault.azure.net/secrets/GATEWAY-CONFIG,identityref:system"
```

**Assign** the secret to the registry

```
az containerapp registry set 
-n <APP_NAME> \
-g <RESOURCE_GROUP> \
--server index.docker.io \
--username <DOCKER_HUB_USER> \
--password "secretref:gateway-config-kv"
```

<figure><img src="https://762006384-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MJXOXEifAmpyvNVL1to%2Fuploads%2FEQHb3Z7k85hQ71bz1rYb%2Freg.png?alt=media&#x26;token=b2a615b9-4d90-4d88-98cc-800a72dae82a" alt=""><figcaption></figcaption></figure>

***

### Enable Shared Memory

The Keeper Gateway requires expanded shared memory (`/dev/shm`) for session recording. This must be applied via a YAML update after the initial creation.

**Export Configuration**

`az containerapp show -n <APP_NAME> -g <RESOURCE_GROUP> -o yaml > keeper-app.yaml`

<figure><img src="https://762006384-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MJXOXEifAmpyvNVL1to%2Fuploads%2FEAVfYobP0zMEkAJYMJ2I%2Fdownload1.png?alt=media&#x26;token=785e36c2-b9bb-4009-a4d2-28850c4cff07" alt=""><figcaption></figcaption></figure>

<figure><img src="https://762006384-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MJXOXEifAmpyvNVL1to%2Fuploads%2FZ0vjkdAkBF7Vf41RqmDF%2Fdownload2.png?alt=media&#x26;token=8696db9b-90e8-40a8-aae1-af6365141670" alt=""><figcaption></figcaption></figure>

**Edit the YAML**

Locate the `template` section and add the `volumes` and `volumeMounts` blocks.

```
template:
  containers:
  - name: <APP_NAME>
    image: keeper/gateway:latest
    env:
    - name: GATEWAY_CONFIG
      secretRef: gateway-config-kv # Use name from Option A or B
    volumeMounts:
    - mountPath: /dev/shm
      volumeName: shm-volume
  volumes:
  - name: shm-volume
    storageType: EmptyDir
```

**Apply the Update**

`az containerapp update -n <APP_NAME> -g <RESOURCE_GROUP> --yaml keeper-app.yaml` &#x20;

#### Operational Commands

| **Action**     | **Command**                                                                                        |
| -------------- | -------------------------------------------------------------------------------------------------- |
| Verify Storage | `az containerapp exec -n <APP_NAME> -g <RESOURCE_GROUP> --command "df -h \| grep shm"`             |
| View Logs      | `az containerapp logs show -n <APP_NAME> -g <RESOURCE_GROUP> --follow`                             |
| Scale to Zero  | `az containerapp scale update -n <APP_NAME> -g <RESOURCE_GROUP> --min-replicas 0 --max-replicas 0` |
| Scale Up       | `az containerapp scale update -n <APP_NAME> -g <RESOURCE_GROUP> --min-replicas 2 --max-replicas 5` |

***

## 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="310.1015625">Destination Endpoint</th><th>Ports Needed</th><th>More Info</th></tr></thead><tbody><tr><td><p><strong>Keeper Cloud</strong><br><code>keepersecurity.[x]</code></p><p></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></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></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>

The Gateway preserves zero knowledge by performing all encryption and decryption of data locally. Keeper Secrets Manager APIs are used to communicate with the Keeper cloud.
