# Deploy Natoma On-Prem (Amazon EKS)

This guide covers deploying the Natoma agent on-premises on Amazon EKS. The on-prem agent connects to the Natoma cloud control plane for orchestration while routing all MCP traffic within your own infrastructure.

***

## Prerequisites

* A running Amazon EKS cluster with `kubectl` and Helm installed
* Access to the Natoma tenant admin panel with Admin permissions
* Your AWS account ID — share this with the Natoma team so they can grant read permissions to the ECR repositories containing the agent image and Helm chart

***

## Network Requirements

You may need to allowlist both inbound and outbound traffic depending on your network configuration.

| Type           | IP Address       | Notes                                                                                             |
| -------------- | ---------------- | ------------------------------------------------------------------------------------------------- |
| Natoma egress  | `35.247.116.223` | May not be utilized for on-prem since traffic will always be unidirectional from agent to Natoma. |
| Natoma ingress | `34.49.218.52`   | Agents will make calls to the Natoma API and auth server.                                         |

***

## Agent Image & Helm Chart

Natoma agent images are hosted on **AWS ECR** in the Natoma AWS org. Share your AWS account ID with the Natoma team — they will grant your account read permissions for the ECR repositories containing the agent image and Helm chart.

The recommended setup uses a dedicated Kubernetes namespace (`natoma`), a ServiceAccount (`natoma-ecr-pull-sa`), and an IAM role (`NatomaECRPullRole`) with ECR pull permissions.

***

## Setup

### Step 1: Retrieve On-Prem Credentials

1. Navigate to your Natoma web tenant at `https://<tenant>.natoma.app`.
2. Log in as an admin and navigate to **Admin** > **On-Premise Deployments**.
3. Create a new deployment, provide an optional name, and proceed.
4. Copy the **Client ID** and **Client Secret** — you will need both when configuring the Helm chart.

{% hint style="warning" %}
Store the Client ID and Client Secret securely. You will reference these values in your Helm configuration.
{% endhint %}

### Step 2: Create an On-Prem MCP Server

1. In the Natoma web app, navigate to **Apps**.
2. Click **Add custom app** and set **App Source Type** to **Remote URL**.
3. Fill out the relevant fields and check **This is an on-prem server**.
4. Enter the remote URL pointing to your on-prem MCP server, including the `/mcp` suffix (or equivalent path pointing directly to the MCP server).

Once the agent is successfully running, the MCP server will be populated with the list of available tool calls.

### Step 3: Configure IAM Permissions

The Natoma pod needs permissions to pull images from the Natoma ECR repository. Create the following IAM policy:

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ECRLoginForSpecificRegistryAndRegion",
      "Effect": "Allow",
      "Action": "ecr:GetAuthorizationToken",
      "Resource": "*"
    },
    {
      "Sid": "PullFromNatomaRepoOnly",
      "Effect": "Allow",
      "Action": [
        "ecr:BatchCheckLayerAvailability",
        "ecr:GetDownloadUrlForLayer",
        "ecr:BatchGetImage",
        "ecr:DescribeImages",
        "ecr:ListImages"
      ],
      "Resource": [
        "arn:aws:ecr:us-east-1:533267197037:repository/natoma/natoma-ai",
        "arn:aws:ecr:us-east-1:533267197037:repository/natoma-helm"
      ]
    }
  ]
}
```

Attach this policy to an IAM role with the following trust policy. Replace `<OIDC_PROVIDER_HOST>` with the OIDC provider of your EKS cluster (format: `oidc.eks.<region>.amazonaws.com/id/<cluster-id>`), `<ACCOUNT_ID>` with your AWS account ID, `<NAMESPACE>` with the Kubernetes namespace, and `<SA_NAME>` with the ServiceAccount name.

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::<ACCOUNT_ID>:oidc-provider/<OIDC_PROVIDER_HOST>"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "<OIDC_PROVIDER_HOST>:aud": "sts.amazonaws.com",
          "<OIDC_PROVIDER_HOST>:sub": "system:serviceaccount:<NAMESPACE>:<SA_NAME>"
        }
      }
    }
  ]
}
```

### Step 4: Create a Namespace and ServiceAccount

Create a `sa.yaml` file for the ServiceAccount:

```yaml
# sa.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: <SA_NAME>
  namespace: <NAMESPACE>
  annotations:
    eks.amazonaws.com/role-arn: <ROLE_ARN>
```

Apply it to your cluster:

```bash
kubectl create namespace <NAMESPACE>       # create the namespace
kubectl apply -f sa.yaml                   # apply the ServiceAccount
kubectl get serviceaccounts -n <NAMESPACE> # verify the SA was created
```

### Step 5: Deploy the Helm Chart

Authenticate against ECR and deploy:

```bash
# Authenticate Helm against ECR
aws ecr --profile <profile> get-login-password --region <AWS_REGION> \
  | helm registry login -u AWS --password-stdin \
    <ACCOUNT_ID>.dkr.ecr.us-east-1.amazonaws.com

# Deploy or upgrade the agent
helm upgrade --install natoma-agent \
  oci://533267197037.dkr.ecr.us-east-1.amazonaws.com/natoma-helm \
  --version <version> \
  --namespace <NAMESPACE> \
  -f <values.yaml override path>
```

### Step 6: Verify Tool Scanning

Once the agent is running, Natoma automatically detects it and initiates tool scanning. Each time the agent polls the Natoma cloud server, any pending scan requests are processed alongside the polling data.

To trigger a manual re-scan at any time, click the more menu icon next to the MCP server in the Natoma web app and select **Scan tools**.

***

## Helm Configuration

### Required Values

The following properties must be provided at install time.

#### `natoma.clientID`

The Client ID generated within the Natoma web application for this clustered deployment.

#### `natoma.clientSecret.*`

Contains `secretName` and `secretKey` properties pointing to the Kubernetes secret that holds the Natoma client secret. The defaults expect a secret named `natoma` with a `client-secret` key.

Create the secret with:

```bash
kubectl create secret generic natoma \
  --from-literal=client-secret=<your-client-secret-here>
```

#### `ingress.host`

The hostname through which MCP traffic will be routed. Must be routable and resolvable by all end-users connecting to MCP servers through the Natoma agent.

#### `image.repository`

Full image name including the repository path. Contact the Natoma team for the ECR repository path.

#### `image.tag`

A specific version tag for the agent image.

#### `serviceAccount.name`

The name of the ServiceAccount that has permissions to pull from the Natoma ECR.

***

### Enabling Audit Logs

To capture audit logs, enable audit logging via the `env` block in your `values.yaml`. Once enabled, agents capture logs in-memory and send them to Natoma every 15 minutes, or when the batch reaches 10,000 entries (both values are configurable).

```yaml
env:
  - name: AUDIT_LOG_ENABLED
    value: "true"
  # Optional overrides:
  - name: AUDIT_LOG_INTERVAL_SEC
    value: "60"   # flush every 1 minute
  - name: AUDIT_LOG_MAX_ENTRIES
    value: "1000" # flush after 1000 entries
```

***

### Optional Values

For help with any of these values, contact the Natoma team or email <support@natomahq.com>.

#### `replicaCount`

Number of agent replicas. Ignored when `autoscaling.enabled: true`.

Default: `2`

#### `autoscaling.enabled`

Set to `true` to enable horizontal pod autoscaling.

Default: `false`

#### `autoscaling.minReplicas`

Minimum replicas during low activity.

Default: `1`

#### `autoscaling.maxReplicas`

Maximum replicas when scaling.

Default: `8`

#### `autoscaling.targetCPUUtilizationPercentage`

CPU utilization percentage to target for horizontal scaling.

Default: `80`

#### `natoma.logLevel`

Supported values: `debug`, `info`, `warn`, `error`. Leave at `info` in production unless advised otherwise by Natoma support.

Default: `info`

#### `natoma.extraCACerts.*`

Enables the agent to validate certificates from MCP servers that use an internal root CA. Configure the root certificates in a Kubernetes ConfigMap containing a single PEM-formatted file.

```bash
kubectl create configmap extra-certs --from-file=/path/to/internal-ca.pem
```

Set `natoma.extraCACerts.configMap` to `extra-certs` and `natoma.extraCACerts.key` to `internal-ca.pem`.

#### `ingress.enabled`

Set to `false` to disable the default `Ingress` resource. May be necessary for complex networking environments or certain managed Kubernetes providers.

Default: `true`

#### `ingress.tls.secretName`

Name of a Kubernetes Secret containing a `crt` key (full certificate chain) and a `key` key (private key).

```bash
kubectl create secret generic example-tls \
  --from-file=crt=/path/to/fullchain.crt \
  --from-file=key=/path/to/privkey.key
```

#### `ingress.tls.hosts`

String array of hostnames matching the certificate's CN and DNS Alternative Names. Use `{}` notation via the Helm CLI:

```bash
--set ingress.tls.hosts={example-natoma.local}
```

#### `ingress.annotations.*`

Optional annotations on the Ingress resource. Escape `.` characters when passing via the Helm CLI:

```bash
--set ingress.annotations."kubernetes\.io/ingress\.class"=nginx
```

#### `env`

Any configurable overrides to agent behavior. Values must be strings.

| Variable                 | Description                                                                                                                                                                                        | Default        |
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- |
| `AUDIT_LOG_ENABLED`      | Set to `"true"` to enable audit log capture and upload                                                                                                                                             | `false`        |
| `AUDIT_LOG_INTERVAL_SEC` | Frequency in seconds at which audit logs are sent to Natoma                                                                                                                                        | `900` (15 min) |
| `AUDIT_LOG_MAX_ENTRIES`  | Maximum entries per audit log batch                                                                                                                                                                | `10000`        |
| `POLLER_INTERVAL_SEC`    | Polling interval in seconds. Controls how often the agent fetches updated policy data, pending scans, etc. Changes made in the Natoma web app won't reflect in on-prem agents until the next poll. | `300` (5 min)  |

***

## Sample `values.yaml`

```yaml
natoma:
  clientId: "your-client-id-here"
  clientSecret:
    secretName: natoma
    secretKey: client-secret

replicaCount: 2

image:
  repository: 533267197037.dkr.ecr.us-east-1.amazonaws.com/natoma/natoma-ai
  pullPolicy: IfNotPresent
  tag: "0.0.15"

service:
  type: ClusterIP
  port: 9090

ingress:
  enabled: true
  host: eks1.sandbox.natomalab.com
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/scheme: internal
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]'
    alb.ingress.kubernetes.io/ssl-redirect: "443"
    alb.ingress.kubernetes.io/certificate-arn: <arn>
    alb.ingress.kubernetes.io/healthcheck-path: /healthz

readinessProbe:
  httpGet:
    path: /healthz
    port: 9090

env:
  - name: AUDIT_LOG_ENABLED
    value: "true"
```

***

## Support

Please reach out to the Natoma team or email <support@natomahq.com>.


---

# Agent Instructions: 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.natoma.ai/hidden/on-prem-eks.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.
