AWS Builder Center

Amazon EKS and Amazon EKS Distro Now Support Kubernetes 1.36

This article walks through User Namespaces and Mutating Admission Policies, two features that reached GA in Kubernetes 1.36, covering how they work, how to configure them, and where to use them. It also covers the release's other Beta features and key points to check before upgrading.

Introduction

On June 2, 2026, AWS announced that Amazon EKS and Amazon EKS Distro now support Kubernetes 1.36. This release includes a wide range of improvements, but the biggest highlight is that two features under development for a long time have finally reached General Availability (GA).
A process running as root inside a container is, in fact, treated as a genuine root user on the host as well. Has that ever left you with a vague sense of unease? Or perhaps you've felt the operational burden of managing certificates and ensuring availability for Admission Webhooks. The two features that reached GA in this release directly address both of these concerns.
This article focuses on these two features, covering what changed, how to configure them, and where they can be applied. It also summarizes the other updates included in this release, so if you're considering upgrading your EKS cluster, we hope you'll find it useful.

What's Changed

Including the two features that address the challenges raised in the previous chapter, here are the four main changes that EKS now supports with Kubernetes 1.36:
FeatureMaturityOverview
User NamespacesGAMaps a container's root user to an unprivileged user on the host, preventing privilege escalation to the host even in the event of a container breakout
Mutating Admission PoliciesGALets you define resource mutations declaratively with CEL (Common Expression Language), evaluated entirely inside the API server without webhook infrastructure
In-Place Pod-Level Resources Vertical ScalingBetaLets you resize a Pod's aggregate CPU and memory budget (spec.resources) in place, without restarting the Pod
Resource Health StatusBetaReflects device health status in a Pod's status, making it easier to identify hardware-related crash loops
Of these, both User Namespaces and Mutating Admission Policies went through the Alpha and Beta stages before reaching GA in 1.36. The former is a change to the container security boundary, and the latter is a change to the admission control architecture. Both have a broad impact, so the following chapters focus on these two features and dive into how they work and how to configure them.
The remaining two Beta features, In-Place Pod-Level Resources Vertical Scaling and Resource Health Status, are covered briefly later in the article along with their use cases.

User Namespaces Reach GA

How it works

User Namespaces use the Linux kernel's user namespace feature to separate the UID/GID a process sees inside a container from the UID/GID actually used on the host. After being introduced as Alpha in 2022, moving to Beta in 2024, and being enabled by default in 2025, the feature has finally reached GA (Stable) in 1.36.
Up to 1.351.36 (Stable)
root (UID 0) inside the containerAlso runs as UID 0 (root) on the hostMapped to an unprivileged UID on the host
Impact of a container breakoutMay gain root privileges on the hostNo privilege escalation to the host occurs
You configure this through the Pod's spec.hostUsers field. Setting hostUsers: false creates a dedicated user namespace for that Pod, and the UID/GIDs inside the container are mapped to a range of unprivileged UID/GIDs on the host. The kubelet and the container runtime manage this mapping automatically, so you don't need to think about the UID range yourself.
According to the Kubernetes blog, even when hostUsers: false is set, capabilities such as CAP_NET_ADMIN only apply to resources inside the container and have no effect on the host.

Configuration

Here's an example Pod manifest:
1
2
3
4
5
6
7
8
9
10
apiVersion: v1
kind: Pod
metadata:
name: userns-demo
spec:
hostUsers: false
containers:
- name: app
image: public.ecr.aws/amazonlinux/amazonlinux:2023
command: ["sleep", "3600"]
To verify the behavior, compare the UID as seen from inside the container with the UID as seen from the node.
1
2
3
4
5
# Inside the container, this shows UID 0 (root)
kubectl exec -it userns-demo -- id

# On the node, the actual process is mapped to an unprivileged UID
kubectl debug node/<NODE_NAME> -it --image=public.ecr.aws/amazonlinux/amazonlinux:2023 -- chroot /host ps -eo pid,uid,user,comm | grep sleep
Inside the container you'll see uid=0(root), while on the node the same process is running under an unprivileged UID.

Prerequisites

User Namespaces reached GA (enabled by default) in 1.36, so there's no need for any additional feature gate configuration on the EKS side. You can use the feature simply by setting hostUsers: false in your Pod manifest.
That said, there are a few prerequisites on the node side. The container runtime must be containerd 2.0 or later (upgrading to 1.36 itself requires containerd 2.0 or later, so this is already satisfied for 1.36 clusters in general). The EKS optimized AL2023 AMI for Kubernetes 1.36 ships with Linux kernel 6.18, containerd 2.2.3, and runc 1.3.4 (per the amazon-eks-ami releases ), which is more than enough to meet User Namespaces' requirements. If you're using the EKS optimized AMI as-is, no additional kernel upgrade is generally needed. Note that User Namespaces is a Linux-only feature and is not available on Windows nodes.

Use cases

User Namespaces are especially effective for multi-tenant SaaS platforms running multiple tenants' workloads on the same cluster, or for environments with strict compliance requirements such as finance, healthcare, and government. Even if a container escape occurs, the impact on the host node and other tenants can be contained, making it easier to achieve a near-zero-trust security model.
The "privileged, but isolated from the host" property also opens up new options for workloads that need capabilities like CAP_NET_ADMIN, such as network diagnostic tools, without granting them privileges on the host.
From a security standpoint, reducing the incident-response cost when a container escape does occur is also a meaningful benefit for operations teams.

Mutating Admission Policies Reach GA

How it works

A Mutating Admission Policy is a mechanism that automatically modifies a resource's content according to rules written in CEL (Common Expression Language) when resources such as Pods are created or updated. It was introduced as Alpha in 2024, moved to Beta in 2025, and reached GA (v1) in 1.36, where it is enabled by default.
Previously, achieving the same kind of mutation required a Mutating Admission Webhook, where kube-apiserver calls out to an external webhook server over HTTPS. Mutating Admission Policy handles this entirely inside kube-apiserver.
Before (Webhook)After (Mutating Admission Policy, GA)
How mutations are writtenWebhook server code (any language)CEL expressions, declared in YAML
Where it runsExternal webhook server (a network hop is required)Inside kube-apiserver
Required infrastructureBuilding a webhook server; issuing, renewing, and managing TLS certificates; ensuring availabilityNone
Impact of a failureDepending on failurePolicy, requests may fail if the webhook server is downDepends on the availability of kube-apiserver itself
Before: Admission Webhook
After: Mutating Admission Policy (GA)

Configuration

Let's look at an example that automatically adds the label team: platform to Pods in the production namespace. It consists of two objects: the policy itself (MutatingAdmissionPolicy) and a binding (MutatingAdmissionPolicyBinding) that determines where it applies.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingAdmissionPolicy
metadata:
name: add-team-label
spec:
matchConstraints:
resourceRules:
- apiGroups: [""]
apiVersions: ["v1"]
operations: ["CREATE"]
resources: ["pods"]
reinvocationPolicy: IfNeeded
mutations:
- patchType: "ApplyConfiguration"
applyConfiguration:
expression: >
Object{
metadata: Object.metadata{
labels: Object.metadata.labels{
"team": "platform"
}
}
}
---
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingAdmissionPolicyBinding
metadata:
name: add-team-label-binding
spec:
policyName: add-team-label
matchResources:
namespaceSelector:
matchLabels:
environment: production
The CEL expression in applyConfiguration.expression builds the "diff" to be applied using the special Object{...} type. Here, it adds team: platform to metadata.labels.
To verify, create a Pod in the target namespace and check whether the label was added automatically:
1
2
3
kubectl label namespace production environment=production
kubectl run nginx --image=nginx -n production
kubectl get pod nginx -n production --show-labels
If the team=platform label appears without going through a webhook server, the policy is working as intended.

Prerequisites

Mutating Admission Policy reached GA (v1) in 1.36 and is enabled by default, so there's no need for any additional feature gate configuration on the EKS side. You can use it simply by creating MutatingAdmissionPolicy / MutatingAdmissionPolicyBinding resources under admissionregistration.k8s.io/v1.
One thing to keep in mind: mutations using ApplyConfiguration cannot modify atomic structs, maps, or arrays. If you need to change such fields, use patchType: JSONPatch instead.

Use cases

Mutating Admission Policy shines in platform engineering scenarios. You can apply common labels to all Pods, set default resource limits, or automatically inject sidecar containers into specific namespaces, all without building a webhook server, and with simpler integration into GitOps pipelines.
The same kinds of mutations can also be achieved with existing policy tools such as OPA Gatekeeper or Kyverno, which rely internally on Mutating Admission Webhooks. With Mutating Admission Policy reaching GA, you now have a choice between replacing these tools or using them alongside it. In fact, Kyverno provides a MutatingPolicy type that extends Mutating Admission Policy, offering a path to migrate gradually while still leveraging your existing policy infrastructure.
Operating a webhook server comes with hidden costs: issuing and renewing TLS certificates, building in redundancy for availability, and maintaining a deployment pipeline. Migrating to Mutating Admission Policy directly reduces these operational costs, which also makes it an easy change to justify from a cost-optimization perspective.

Other Updates

This chapter briefly covers the remaining two features that reached Beta in 1.36, focusing on what they are and their use cases.

In-Place Pod-Level Resources Vertical Scaling (Beta)

"Pod-level Resources," which reached Beta in 1.34, added a spec.resources field to Pods that lets multiple containers share a single CPU/memory pool. In 1.36, this Pod-level resource budget can be resized in place, without a restart (InPlacePodLevelResourcesVerticalScaling, enabled by default).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: v1
kind: Pod
metadata:
name: shared-pool-demo
spec:
resources:
requests:
cpu: "1"
memory: "1Gi"
limits:
cpu: "2"
memory: "2Gi"
containers:
- name: app
image: nginx
- name: sidecar
image: envoy
Using the resize subresource, as in kubectl patch pod shared-pool-demo --subresource resize --patch '{"spec":{"resources":{"limits":{"cpu":"4"}}}}', you can change this Pod's overall CPU limit in place. This is useful when you want to expand the shared CPU/memory budget for an application container and its sidecar together during a traffic spike.

Resource Health Status (Beta)

For workloads using GPUs or other specialized devices, when a Pod enters a crash loop it can take time to determine whether the cause is an application bug or a device issue. Resource Health Status (KEP-4680) reflects the health state (Healthy / Unhealthy / Unknown) of devices allocated through Device Plugins or DRA (Dynamic Resource Allocation) in the Pod's status.
When a crash loop occurs, checking the device health in the Pod's status lets you immediately distinguish between a hardware-related crash loop and an application-related one, streamlining on-call response for ML inference and GPU batch workloads.

Upgrade Guide

Check in advance with cluster insights

Upgrading a Kubernetes version might look like simply bumping the control plane version, but in practice there's quite a lot worth checking beforehand, such as the compatibility of your existing manifests and APIs, and fields that are being deprecated. EKS provides cluster insights, which lets you check, from the "Upgrade insights" tab in the Amazon EKS console, whether your current cluster has any issues that could cause problems when upgrading to 1.36. If issues are found, fix them, re-run the check to confirm they're resolved, and then proceed with the upgrade.

Action required for 1.36

Beyond new features, the 1.36 release notes call out several changes as "Action required." Before upgrading to 1.36, it's worth checking the following three items in particular.

Complete removal of the gitRepo volume

The gitRepo volume type is completely disabled in 1.36. The API still accepts Pods that use this volume, but the kubelet refuses to run them. If you have manifests that use gitRepo, migrate to an init container or a git-sync sidecar.

Changes to SELinux volume labeling (GA)

On nodes with SELinux enabled, volume labeling now defaults to the mount -o context-based approach. This can cause issues if the same volume is shared between privileged and unprivileged Pods, so review your seLinuxChangePolicy settings beforehand.

Strict IP/CIDR validation enabled by default

API fields containing IP addresses with leading zeros (e.g., 010.000.000.005) or non-canonical CIDR notation (e.g., 192.168.0.5/24) are now rejected on create and update. Check your manifests, Helm charts, and IaC code for these patterns.

Check your add-on versions

In addition to cluster insights, make sure add-ons such as CoreDNS, kube-proxy, and the VPC CNI are running versions compatible with 1.36. Even after upgrading the control plane to 1.36, outdated add-on versions can still cause issues.

If you're using EKS Distro

If you're using EKS Distro, 1.36 builds are available from the ECR Public Gallery or GitHub.

If you put off upgrading

EKS Kubernetes versions are under standard support for 14 months after release, followed by 12 months of extended support. For 1.36, standard support ends on August 2, 2027, and extended support ends on August 2, 2028. You can keep running a cluster during extended support, but it comes with an additional cost per cluster hour. The longer you put off upgrading, the more these additional costs and required changes tend to accumulate, which is worth keeping in mind when planning your upgrade schedule.

Summary

With Kubernetes 1.36 support, Amazon EKS and Amazon EKS Distro have brought User Namespaces and Mutating Admission Policies to GA. The former is a fundamental rework of the container security boundary, and the latter of the admission control architecture. This article focused on these two features, how they work and how to configure them, and also covered Beta features such as In-Place Pod-Level Resources Vertical Scaling and Resource Health Status, along with what to check when upgrading.
Both features work without any additional configuration on the EKS side. Simply upgrade your cluster to 1.36 to try them out. We recommend starting in a test environment by trying a Pod with hostUsers: false and a MutatingAdmissionPolicy for yourself.
When planning a production upgrade, checking cluster insights upfront, along with the 1.36-specific items covered in this article (the gitRepo volume, SELinux labeling, and Strict IP/CIDR Validation), should help the migration go smoothly.

References

Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article