> For the complete documentation index, see [llms.txt](https://docs.openiam.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.openiam.com/installation/kubernetes/amazon-eks.md).

# Amazon EKS

Create and prepare an Amazon EKS cluster for OpenIAM — node sizing, EBS and EFS storage, node settings, and the entry point.

This page covers what EKS needs **in addition to** [*Prepare the cluster*](/installation/kubernetes/prepare-the-cluster.md). Work through that page as well; it carries the requirements common to every cluster.

## What this covers, and how long it takes

|                |                                                                      |
| -------------- | -------------------------------------------------------------------- |
| **You get**    | An EKS cluster ready for an OpenIAM deployment                       |
| **Time**       | 60–90 minutes, most of it waiting on AWS                             |
| **Hosts**      | Your AWS account, and a machine with `kubectl`, Helm and the AWS CLI |
| **Downtime**   | None                                                                 |
| **Reversible** | Yes                                                                  |

## Before you start

* Permission to create an EKS cluster, node groups, IAM roles, EBS and EFS resources.
* The AWS CLI, `kubectl` and Helm on the machine you will deploy from.
* [*Managed databases*](/installation/rpm/cloud/managed-databases.md), because the database is provisioned separately and its parameters must be right before the deployment runs.

## Set these first

{% code overflow="wrap" %}

```bash
export CLUSTER=<your EKS cluster name>
export AWS_REGION=<your region>
export EFS_ID=<the EFS file system id, once you create it in step 5>
export DIAG_IMAGE=<a small utility image with a shell, reachable from your cluster>
```

{% endcode %}

**Pin the diagnostic image to a version.** `busybox:1.36` is a common choice. On a restricted network, mirror one into your own registry and use that rather than pulling `latest` from a public registry.

***

## Prepare it

### 1. Create the cluster

**The Kubernetes version this release is configured for** — see [*System requirements*](/installation/system-requirements.md). The Terraform route sets it for you.

Place the worker nodes in **private subnets**, with a NAT gateway for the egress in [*Prepare the cluster*](/installation/kubernetes/prepare-the-cluster.md) step 5. Whether the API endpoint is public, private or both is your organisation's decision; the deployment only needs your own access to it.

### 2. Size the node group

The deployment needs 32 GB of memory for non-production, 40 GB for production, and 8 CPU — as a total across the nodes running it.

| Nodes | Instance type | Gives                                                                  |
| ----- | ------------- | ---------------------------------------------------------------------- |
| 2     | `m5.2xlarge`  | 16 vCPU, 64 GB — comfortable headroom for non-production               |
| 3     | `m5.2xlarge`  | Room for production, and for a node to be lost during a rolling update |

**`m4.xlarge` is the smallest tested instance type.** Below that, pods schedule and then evict under load, which reads as an application fault.

**Size for a node loss.** A single OpenIAM deployment tolerates losing a node only if the remaining nodes can take its pods — that is what makes the cluster the availability layer rather than the platform.

### 3. Set `vm.max_map_count` on the nodes

The search tier requires it and the chart does not set it. Put it in the node group's launch template user data:

{% code overflow="wrap" %}

```bash
#!/bin/bash
sysctl -w vm.max_map_count=262144
echo 'vm.max_map_count=262144' >> /etc/sysctl.d/99-openiam.conf
```

{% endcode %}

**Confirm on a running node** before you deploy:

{% code overflow="wrap" %}

```bash
kubectl debug "node/$(kubectl get nodes -o name | head -1 | cut -d/ -f2)" \
  -it --image="$DIAG_IMAGE" -- sysctl vm.max_map_count
```

{% endcode %}

**Expected: `262144`.**

### 4. Install the EBS CSI driver, and make a class default

EKS does not install the EBS CSI driver by default, and without it no volume binds.

{% code overflow="wrap" %}

```bash
aws eks create-addon --cluster-name "$CLUSTER" --addon-name aws-ebs-csi-driver
```

{% endcode %}

The node role needs the EBS CSI policy attached, or an IAM role for the service account.

Then confirm exactly one class is default:

{% code overflow="wrap" %}

```bash
kubectl get storageclass
```

{% endcode %}

**Expected:** a `gp2` or `gp3` class marked `(default)`. If none is:

{% code overflow="wrap" %}

```bash
kubectl patch storageclass gp3 \
  -p '{"metadata":{"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
```

{% endcode %}

### 5. Provide `ReadWriteMany` storage with EFS

**EBS cannot do `ReadWriteMany`**, and several OpenIAM components need it — see [*Prepare the cluster*](/installation/kubernetes/prepare-the-cluster.md) step 3. On EKS that means EFS.

1. **Create an EFS file system** in the cluster's VPC, with a mount target in each subnet the nodes run in.
2. **Allow NFS (2049)** from the node security group to the mount targets' security group.
3. **Install the EFS CSI driver:**

   <pre class="language-bash" data-overflow="wrap"><code class="lang-bash">aws eks create-addon --cluster-name "$CLUSTER" --addon-name aws-efs-csi-driver
   </code></pre>
4. **Create a storage class** for it:

   <pre class="language-yaml" data-overflow="wrap"><code class="lang-yaml">apiVersion: storage.k8s.io/v1
   kind: StorageClass
   metadata:
     name: openiam-rwx
   provisioner: efs.csi.aws.com
   parameters:
     provisioningMode: efs-ap
     fileSystemId: $EFS_ID
     directoryPerms: "700"
   </code></pre>
5. **Test it** with the `ReadWriteMany` PVC in [*Prepare the cluster*](/installation/kubernetes/prepare-the-cluster.md) step 3 before going further. This is the check most worth doing early — it is the one that fails late and confusingly if it is wrong.

### 6. Provision the database

Use RDS. [*Managed databases*](/installation/rpm/cloud/managed-databases.md) covers the supported engines and the parameter group settings that must be applied before the deployment runs.

**Allow the engine's port from the node security group to the RDS security group**, and test it from the cluster with the check in [*Prepare the cluster*](/installation/kubernetes/prepare-the-cluster.md) step 7.

### 7. Plan the entry point

Users reach the platform through the reverse proxy's service. Expose it with a **Network Load Balancer** or an **Application Load Balancer** through the AWS Load Balancer Controller, according to your organisation's convention.

| Setting                       | Value                                                                |
| ----------------------------- | -------------------------------------------------------------------- |
| **Health check path**         | `/idp/login`                                                         |
| **Backend protocol and port** | HTTP, the reverse proxy service's port                               |
| **TLS**                       | An ACM certificate at the load balancer, or terminate in the cluster |

**Check `/idp/login`, not `/`.** It exercises the proxy and a real application behind it.

Whatever DNS name resolves to that load balancer is the address you give the platform during first sign-in — [*First sign-in*](/installation/rpm/rpm-single-node/first-sign-in.md) covers the content provider, which works the same way on Kubernetes.

***

## Verify it

{% code overflow="wrap" %}

```bash
kubectl version -o json | jq -r '.serverVersion.gitVersion'
kubectl get nodes -o wide
kubectl get storageclass
kubectl get csidrivers
```

{% endcode %}

**Expected:** the release's Kubernetes version, nodes `Ready` in private subnets, a default EBS class, an EFS class, and both CSI drivers registered. Then run the full pass in [*Prepare the cluster*](/installation/kubernetes/prepare-the-cluster.md).

## If it goes wrong

| What you see                                 | What it means                                              | What to do                                                                               |
| -------------------------------------------- | ---------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| Every PVC stays `Pending`                    | No default storage class, or the EBS CSI driver is missing | Install the add-on and mark a class default                                              |
| Only the shared-storage PVCs stay `Pending`  | EFS is not reachable, or the class is wrong                | Check the mount targets, the NFS rule on 2049, and the file system ID in the class       |
| The search tier crashes on start             | `vm.max_map_count` is below 262144                         | Set it in the launch template and roll the nodes                                         |
| Pods schedule then evict                     | The node group is too small for the deployment             | Add nodes, or move to a larger instance type                                             |
| A pod cannot resolve any DNS name            | This can follow a force-deleted pod on EKS                 | **Never delete an OpenIAM pod with `--force`.** Delete it normally and let it reschedule |
| Images will not pull                         | No egress to the registry, or the pull secret is wrong     | Check the NAT route, then the credentials from your account team                         |
| The database is unreachable from the cluster | Security group                                             | Allow the engine's port from the node security group                                     |

## What this procedure does not cover

Your account structure, VPC design and cluster policies. The [Solution Architecture and Design Guide](/solution-architecture/deployment/network-design.md) covers the design decisions.

## Related

* [*Prepare the cluster*](/installation/kubernetes/prepare-the-cluster.md) — do this as well
* [*Managed databases*](/installation/rpm/cloud/managed-databases.md)
* [*System requirements*](/installation/system-requirements.md)

*Applies to OpenIAM 2026.8.1.*


---

# 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 by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.openiam.com/installation/kubernetes/amazon-eks.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
