Дата публикации
ai_products

Как запустить автономного ИИ-агента OpenClaw на AKS и не сжечь прод: микровиртуалки Kata против побегов из контейнеров

Что нового

Microsoft показала готовый рецепт, как «закалить» автономного ИИ-агента OpenClaw на Azure Kubernetes Service (AKS), чтобы один зловредный скилл не превратил кластер в решето.

Ключевые новшества по сравнению с обычным запуском OpenClaw в контейнере:

  • Изоляция через microVM, а не только через namespaces cgroups:
    • каждый pod с OpenClaw работает внутри отдельной микровиртуалки Kata Containers;
    • граница безопасности — гипервизор (KVM / MSHV), а не только ядро Linux на ноде.
  • Специальный node pool в AKS под Kata:
    • создаётся пул с --workload-runtime KataMshvVmIsolation;
    • в нём включён runtimeClass kata-vm-isolation;
    • используются VM‑типы с поддержкой nested virtualization (D‑series v3/v5, E‑series v3/v5 и др.).
  • Полноценная прод-конфигурация для OpenClaw:
    • два реплики gateway с rolling update;
    • постоянное хранилище на Azure Files NFS (PV + PVC, ReadWriteMany);
    • ConfigMap с конфигом openclaw.json и CORS;
    • Secret с токеном авторизации, прокинутым в контейнер как AUTH_TOKEN;
    • TLS‑терминация на Application Gateway for Containers через Gateway API (Gateway + HTTPRoute).
  • Проверка реальной изоляции:
    • демонстрация, что внутри pod нельзя «дотянуться» до корня файловой системы хоста через /proc/1/root;
    • в обычном контейнере это даёт доступ к /etc/kubernetes и другим чувствительным данным, в microVM — нет.

Это не новый продукт, а именно практическая схема: как безопасно запускать OpenClaw, который по своей природе требует «God Mode» доступ к файловой системе и API, но при этом не должен становиться точкой входа в вашу внутреннюю сеть.

Как это работает

Проблема: OpenClaw как «God Mode» агент

OpenClaw — это open‑source автономный ИИ‑агент для продвинутых пользователей и разработчиков. Он умеет через чат‑клиенты вроде WhatsApp или Telegram:

  • читать и разбирать почту;
  • работать с файлами;
  • планировать задачи и встречи;
  • выполнять произвольные «Skills» (плагины, задания, код).

Чтобы всё это работало, OpenClaw часто запускают:

  • с широкими правами к файловой системе пользователя;
  • с доступом к внутренним API и секретам;
  • нативно на машине, без жёсткого sandbox.

Отсюда парадокс: агент полезен только тогда, когда у него почти полный доступ. Но один злонамеренный скилл или успешная prompt‑инъекция способны превратить его в точку полного компромисса системы. В оригинальном материале это связывают с уязвимостями уровня CVE‑2026‑25253: одна брешь — и агент становится каналом для lateral movement и утечки данных в вашей сети.

Почему контейнеров мало

Если вы запускаете OpenClaw в Kubernetes, кажется, что контейнер уже даёт изоляцию. На практике граница безопасности гораздо тоньше, чем у виртуальной машины:

  1. Общее ядро:

    • контейнеры делят ядро хоста;
    • уязвимость в ядре (privilege escalation) позволяет процессу внутри контейнера получить root‑доступ к ноде.
  2. Избыточные привилегии и неправильная конфигурация:

    • --privileged;
    • широкие Linux‑capabilities;
    • hostPath‑монтирования;
    • доступ к Docker‑сокету;
    • проброс устройств вроде /dev/kvm, /dev/fuse.

    Всё это открывает прямой путь к управлению хостом.

  3. Пробои границ файловой системы и namespaces:

    • ошибки с mount‑namespaces;
    • запись в host‑монтирования;
    • неправильная работа с chroot / pivot_root.

    В результате контейнер начинает видеть файлы и креденшелы хоста.

  4. Риски supply chain:

    • зловредный образ или зависимость стартуют внутри контейнера и дальше пытаются вылезти наружу.
  5. Большой blast radius:

    • после компромисса ноды атакующий получает:
      • токены сервис‑аккаунтов;
      • креденшелы к реестрам;
      • доступ к kubelet и runtime;
      • возможность читать трафик и ходить по другим pod’ам и кластерам.

Для OpenClaw это особенно опасно: он запускает код и плагины от разных команд и даже сторонних разработчиков. Мягкая изоляция контейнеров здесь не выдерживает модель угроз, где вы заранее предполагаете враждебный код.

Решение: microVM и Kata Containers

MicroVM — это облегчённые виртуальные машины, оптимизированные под контейнероподобные нагрузки:

  • используют аппаратную виртуализацию (KVM / MSHV);
  • урезанный device‑model и короткий путь загрузки;
  • меньше overhead, чем у «полноценной» VM, но при этом есть гипервизорная граница.

Kata Containers реализуют идею «OCI‑контейнеры внутри VM»:

  • для Kubernetes это выглядит как обычный контейнерный runtime;
  • каждый pod‑sandbox получает свою microVM с гостевым ядром Linux;
  • изоляция строится не только на namespaces/cgroups, а на гипервизоре.

Что это даёт для OpenClaw:

  • Сильная граница изоляции:

    • эксплойт ядра Linux внутри агента бьёт по гостевому ядру microVM, а не по ядру ноды;
    • чтобы добраться до хоста, атакующему нужно ещё и прорвать гипервизор.
  • Суженный blast radius:

    • компромисс ограничен конкретной microVM и pod’ом;
    • переход к соседним нагрузкам на ноде сильно усложняется.
  • Контролируемая поверхность атаки:

    • минимальный набор устройств;
    • меньше host‑монтирований и проброшенных девайсов;
    • жёстче дефолтные привилегии.
  • Defense‑in‑depth:

    • внутри microVM вы по‑прежнему можете включать:
      • seccomp‑профили;
      • drop‑capabilities;
      • read‑only rootfs;
      • LSM (AppArmor/SELinux);
    • но поверх этого есть ещё и гипервизор.
  • Лучше подходит для враждебных multi‑tenant сценариев:

    • когда OpenClaw исполняет сторонние плагины, задания и код, Kata‑sandbox выглядит гораздо разумнее, чем «голый» контейнер.

Архитектура решения на AKS

Архитектура строится вокруг Kubernetes и Kata Containers, но для разработчика всё остаётся в контейнерной парадигме: OCI‑образы, Deployment, Service, Gateway API.

Ключевые элементы:

  1. Application Gateway for Containers (ALB)

    • принимает HTTPS‑трафик от клиентов (WhatsApp, Discord и др. через интеграции);
    • реализует TLS‑терминацию на уровне Gateway ресурса.
  2. AKS как оркестратор

    • управляет жизненным циклом pod’ов OpenClaw и его Skills;
    • применяет политики и распределяет нагрузку.
  3. containerd + Kata runtimeClass

    • containerd настроен на использование kata-vm-isolation для нужных pod’ов;
    • каждый такой pod запускается внутри microVM.
  4. KVM‑бэкенд для microVM

    • на нодах используется AzureLinux с поддержкой KVM/МSHV;
    • node pool создаётся с --workload-runtime KataMshvVmIsolation.
  5. Azure Files NFS для стейта

    • PersistentVolume на базе Azure Files NFS с ReadWriteMany;
    • хранит рабочее пространство OpenClaw: историю диалогов, конфиги, загруженные файлы.

Поток запросов:

  1. Пользователь отправляет запрос (например, через WhatsApp‑бота).
  2. Трафик попадает в Azure Application Gateway for Containers.
  3. Gateway ресурс в Kubernetes принимает HTTPS‑соединение и по HTTPRoute отдаёт его в openclaw-gateway-service.
  4. Service направляет запрос в один из pod’ов openclaw-gateway, которые работают внутри Kata microVM.
  5. Агент читает/пишет данные в Azure Files через PV/PVC.
  6. Ответ возвращается пользователю через тот же Application Gateway.

С точки зрения безопасности самое важное: даже если злоумышленник добился выполнения кода в контейнере OpenClaw, ему нужно ещё взломать границу microVM, чтобы добраться до ноды и других pod’ов.

Что это значит для вас

Кому это реально нужно

Этот подход полезен, если вы:

  • запускаете OpenClaw в корпоративной среде с чувствительными данными;
  • даёте агенту доступ к внутренним API, CRM, хранилищам документов;
  • позволяете сторонним командам или внешним разработчикам писать свои Skills/плагины;
  • используете общий AKS‑кластер для нескольких продуктов и не хотите, чтобы один агент стал точкой входа в остальное.

В таких сценариях запуск OpenClaw «просто в контейнере» — слабое звено. MicroVM‑изоляция через Kata уменьшает вероятность того, что один успешный побег из контейнера превратится в компромисс всей ноды и кластера.

Когда можно обойтись без этого

Если вы:

  • запускаете OpenClaw локально на личной машине только для себя;
  • используете его в отдельном тестовом кластере, полностью изолированном от прод‑ресурсов;
  • не даёте агенту доступ к внутренним сетям и важным данным,

то сложность с AKS, Kata и Application Gateway может быть избыточной. В таких случаях проще и дешевле ограничиться классическим hardening контейнера:

  • минимальные образы;
  • отключённый --privileged;
  • строгие seccomp‑профили;
  • отсутствие hostPath и доступа к Docker‑сокету.

На что обратить внимание при внедрении

Плюсы подхода:

  • сильная изоляция между OpenClaw и остальными ворклоадами на ноде;
  • понятная модель угроз: чтобы добраться до кластера, нужно взломать и OpenClaw, и microVM/hypervisor;
  • сохраняется привычный DevOps‑флоу: Docker‑образы, Helm‑чарты, Kubernetes‑манифесты.

Минусы и ограничения:

  • вам нужен AKS и Azure‑инфраструктура (NFS Files, Application Gateway for Containers);
  • нужен node pool с nested virtualization (не все VM‑типы подойдут);
  • microVM‑подход почти всегда даёт чуть больший overhead по старту pod’ов и ресурсам, чем «голые» контейнеры;
  • конфигурация сложнее: PV/PVC, Gateway API, TLS, Secrets, ConfigMap, отдельный пул под Kata.

Если вы работаете из России, нужно учитывать:

  • доступ к Azure и AKS может потребовать VPN и юридическую проработку;
  • без стабильного доступа к Azure этот сценарий не взлетит.

Практический вывод

  • Для прод‑запуска OpenClaw с реальными пользователями и доступом к данным: имеет смысл сразу проектировать архитектуру с microVM‑изоляцией.
  • Для прототипов и pet‑projects: можно стартовать в обычных контейнерах, но держать в голове, что в момент выхода в прод придётся переехать на более жёсткий sandbox.

Место на рынке

Речь идёт не о новой ИИ‑модели, а об архитектурном паттерне для запуска автономных агентов. Прямых «конкурентов» здесь несколько типов:

  1. Обычные контейнеры в Kubernetes

    • плюс: минимальные накладные расходы, простота;
    • минус: общая поверхность атак ядра, высокая цена ошибки при побеге из контейнера.
  2. Отдельные виртуальные машины под каждый агент

    • плюс: сильная изоляция;
    • минус: тяжёлые, дорогие, медленно стартуют, неудобны для оркестрации множества короткоживущих задач.
  3. Специализированные sandbox‑решения (gVisor, Firecracker и др.)

    • дают разные варианты усиленной изоляции контейнеров;
    • интеграция и поддержка сильно зависят от конкретного облака и стеков.

Kata Containers в AKS занимают промежуточную позицию:

  • изоляция ближе к отдельным VM, чем к стандартным контейнерам;
  • при этом сохраняется Kubernetes‑оркестрация и OCI‑образ;
  • решение глубоко интегрировано в Azure (AKS + Application Gateway for Containers + Azure Files).

Точных чисел по сравнению производительности с обычными контейнерами или отдельными VM в материале нет. Можно лишь сказать, что microVM‑подход проектировался как компромисс: безопасность уровня VM при накладных расходах, приемлемых для контейнерных ворклоадов.

Установка

Ниже — полный путь развертывания решения на AKS. Команды из оригинального гайда сохранены без изменений.

Предварительные требования

Вам нужно заранее подготовить:

  • AKS‑кластер в Azure;
  • Azure NFS File Share c включённым private link;
  • Application Gateway for Containers, управляемый ALB‑контроллером;
  • настроенный kubectl, указывающий на ваш кластер;
  • авторизованный az CLI с нужной подпиской.

Инициализация переменных окружения

export cluster_name=<CLUSTER_NAME>
export resource_group=<RESOURCE_GROUP>

Создаём AKS node pool с Kata VM Isolation

Pod’ы OpenClaw gateway требуют runtimeClassName: kata-vm-isolation. Нужен отдельный пул нод с поддержкой этого runtime.

az aks nodepool add \
  --resource-group $resource_group \
  --cluster-name $cluster_name \
  --name katanp \
  --node-count 2 \
  --node-vm-size Standard_D4s_v3 \
  --os-sku AzureLinux \
  --workload-runtime KataMshvVmIsolation \
  --labels agentpool=katanp

Важно:

  • --workload-runtime KataMshvVmIsolation включает runtimeClass kata-vm-isolation на пуле нод.
  • Размер VM должен поддерживать nested virtualization (D‑series v3/v5, E‑series v3/v5 и т.п.).

Создаём NFS Persistent Volume

Используется Azure Files NFS для постоянного хранилища рабочего пространства OpenClaw. Сначала создаём PV.

Замените volumeHandle и volumeAttributes на свои значения Azure Files.

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolume
metadata:
  name: openclaw-nfs-pv
spec:
  capacity:
    storage: 100Gi
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  mountOptions:
    - sec=sys
    - noresvport
    - actimeo=30
  csi:
    driver: file.csi.azure.com
    volumeHandle: <resource-group>#<storage-account>#<share-name>
    volumeAttributes:
      resourceGroup: <resource-group>
      shareName: <share-name>
      protocol: nfs
      server: <storage-account>.privatelink.file.core.windows.net
EOF

Проверяем, что PV создан:

kubectl get pv openclaw-nfs-pv

Создаём NFS PersistentVolumeClaim

PVC привязывается к созданному PV. Deployment использует PVC pvc-openclaw-nfs.

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  # The name of the PVC
  name: pvc-openclaw-nfs
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      # The real storage capacity in the claim
      storage: 50Gi
  # This field must be the same as the storage class name in StorageClass
  storageClassName: ""
  volumeName: openclaw-nfs-pv
EOF

Убедитесь, что PVC в статусе Bound.

Создаём ConfigMap с конфигом OpenClaw

ConfigMap отдаёт pod’ам файл openclaw.json с настройками CORS и токена gateway. Замените allowedOrigins на свой фронтенд ALB.

Важно: токен храните как переменную, не в открытом виде в манифесте.

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
  name: openclaw-config
data:
  openclaw.json: |
    {
      "gateway": {
        "auth": {
          "token": "${AUTH_TOKEN}"
        },
        "controlUi": {
          "allowedOrigins": [
            "https://<YOUR ALB FRONTEND URL>.alb.azure.com"
          ]
        }
      }
    }
EOF

Создаём Secret с токеном авторизации

Gateway OpenClaw требует токен для доступа. Deployment читает его из Secret openclaw-auth-token и прокидывает в переменную AUTH_TOKEN.

Генерируем токен и создаём Secret:

# Generate a random 32-byte hex token
AUTH_TOKEN=$(openssl rand -hex 32)
echo "$AUTH_TOKEN"   # save this — you'll need it to authenticate with the gateway

kubectl create secret generic openclaw-auth-token \
  --from-literal=token="$AUTH_TOKEN"

Если Secret не существует к моменту применения Deployment, pod’ы упадут с CreateContainerConfigError.

Деплой OpenClaw Gateway

Это основной Deployment приложения. Он зависит от:

  • Kata node pool (runtimeClassName: kata-vm-isolation, nodeSelector: agentpool=katanp);
  • PVC pvc-openclaw-nfs;
  • ConfigMap openclaw-config.

Особенности:

  • 2 реплики с rolling update;
  • init‑контейнер копирует конфиг в writable volume;
  • порт 18789;
  • liveness/readiness‑пробы на /health;
  • запросы ресурсов: 500m CPU, 2Gi RAM;
  • лимиты: 1000m CPU, 4Gi RAM.
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: openclaw-gateway
spec:
  replicas: 2
  selector:
    matchLabels:
      app: openclaw-gateway
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
      maxSurge: 1
  template:
    metadata:
      labels:
        app: openclaw-gateway
    spec:
      runtimeClassName: kata-vm-isolation
      nodeSelector:
        agentpool: katanp
      securityContext:
        fsGroup: 1000
      initContainers:
        - name: copy-openclaw-config
          image: alpine/openclaw:latest
          env:
            - name: HOME
              value: /writable
          command:
            - sh
            - -c
            - |
              cp /config/openclaw.json /writable/openclaw.json \
              && chown 1000:1000 /writable/openclaw.json \
              && echo "--- Config file contents ---" \
              && cat /writable/openclaw.json
          volumeMounts:
            - name: openclaw-config-volume
              mountPath: /config
            - name: openclaw-writable
              mountPath: /writable
      containers:
        - name: gateway
          image: alpine/openclaw:latest
          ports:
            - containerPort: 18789
          env:
            - name: NODE_OPTIONS
              value: "--max-old-space-size=4096"
            - name: AUTH_TOKEN
              valueFrom:
                secretKeyRef:
                  name: openclaw-auth-token
                  key: token
          # Start gateway the way the tutorial indicates
          command: ["openclaw", "gateway"]
          args: ["run", "--allow-unconfigured", "--bind", "lan"]
          volumeMounts:
            - name: openclaw-writable
              mountPath: /home/node/.openclaw
            - name: openclaw-data
              mountPath: /home/node/workspace
              subPath: workspace
          resources:
            requests:
              cpu: "500m"
              memory: "2Gi"
            limits:
              cpu: "1000m"
              memory: "4Gi"
          livenessProbe:
            httpGet:
              path: /health
              port: 18789
            initialDelaySeconds: 60
            periodSeconds: 15
            failureThreshold: 3
          readinessProbe:
            httpGet:
              path: /health
              port: 18789
            initialDelaySeconds: 10
            periodSeconds: 5
      volumes:
        - name: openclaw-data
          persistentVolumeClaim:
            claimName: pvc-openclaw-nfs
        - name: openclaw-config-volume
          configMap:
            name: openclaw-config
            items:
              - key: openclaw.json
                path: openclaw.json
        - name: openclaw-writable
          emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
  name: openclaw-gateway-service
spec:
  type: ClusterIP
  selector:
    app: openclaw-gateway
  ports:
    - protocol: TCP
      port: 18789
      targetPort: 18789
EOF

Проверяем, что Deployment поднялся и pod’ы в статусе Running и READY 2/2:

kubectl get deployment openclaw-gateway
kubectl get pods -l app=openclaw-gateway

Создаём TLS‑секрет для HTTPS

Application Gateway for Containers использует Secret gateway-tls-secret для TLS‑терминации. В гайде — self‑signed сертификат, в проде используйте сертификат от доверенного CA.

kubectl create secret tls gateway-tls-secret \
  --cert=<path-to-tls-cert> \
  --key=<path-to-tls-key>

Создаём Gateway (Gateway API)

Gateway описывает HTTPS‑листенер на ALB. Обновите аннотацию alb.network.azure.com/application-gateway-id под свой ресурс ALB.

cat <<EOF | kubectl apply -f -
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: https
  annotations:
    alb.network.azure.com/application-gateway-id: /subscriptions/<subscription id>/resourceGroups/mc_openclaw_openclaw-cluster_centralus/providers/Microsoft.ServiceNetworking/trafficControllers/<alb id>
    alb.networking.azure.io/alb-namespace: default
    alb.networking.azure.io/alb-name: alb-openclaw
spec:
  gatewayClassName: azure-alb-external
  listeners:
    - name: https
      protocol: HTTPS
      port: 443
      allowedRoutes:
        namespaces:
          from: All
      tls:
        mode: Terminate
        certificateRefs:
        - kind: Secret
          group: ""
          name: gateway-tls-secret
EOF

kubectl get gateway https

Ждём, пока у Gateway появится Programmed=True.

Создаём HTTPRoute

HTTPRoute связывает Gateway с backend‑сервисом. Весь трафик (/) с HTTPS‑Gateway уходит в openclaw-gateway-service на порт 18789.

cat <<EOF | kubectl apply -f -
kind: HTTPRoute
apiVersion: gateway.networking.k8s.io/v1
metadata:
  name: http-route
spec:
  parentRefs:
    - name: https
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /  
    backendRefs:
    - name: openclaw-gateway-service
      kind: Service
      namespace: default
      port: 18789
EOF

Как запустить и проверить

Получаем внешний endpoint

kubectl get gateway https -o jsonpath='{.status.addresses[0].value}'

Откройте этот адрес в браузере. Если вы используете self‑signed сертификат, браузер покажет предупреждение «Not secure» — перейдите через Advanced.

Аутентификация и pairing

На экране логина введите Gateway Token (тот самый AUTH_TOKEN). OpenClaw ответит ошибкой pairing required — это ожидаемо.

OpenClaw требует pairing при первом подключении нового устройства, браузера или CLI‑клиента к gateway.

Одобряем pairing для обоих pod’ов:

POD=$(kubectl get pod -l app=openclaw-gateway -o jsonpath='{.items[0].metadata.name}')
POD2=$(kubectl get pod -l app=openclaw-gateway -o jsonpath='{.items[1].metadata.name}')
TOKEN=$(kubectl get secret openclaw-auth-token -o jsonpath='{.data.token}' | base64 -d)

kubectl exec "$POD" -c gateway -- openclaw devices approve --latest --token "$TOKEN"
kubectl exec "$POD2" -c gateway -- openclaw devices approve --latest --token "$TOKEN"

После сообщения об успешном pairing можно снова открыть веб‑интерфейс OpenClaw и начать работу.

Тестируем изоляцию microVM

Проверим, видит ли pod корневую файловую систему ноды через /proc/1/root.

kubectl exec -it "$POD" -c gateway -- ls /proc/1/root/etc/kubernetes 2>&1

Ожидаемый результат — ошибка вида:

ls: cannot access '/proc/1/root/etc/kubernetes': No such file or directory

В обычном контейнере PID 1 внутри контейнера — это процесс на ядре хоста, и /proc/1/root указывает на root‑файловую систему ноды, включая /etc/kubernetes с креденшелами kubelet. В случае Kata PID 1 живёт внутри гостевой ОС microVM, и до файлов хоста таким способом не дотянуться.

Это и есть практическое подтверждение: OpenClaw работает в изолированной microVM, а не на общем ядре ноды.


Читайте также