Giving the Copilot SDK Agent a "hardware-level helmet" using Kata microVM on AKS
Recently, I was working on creating a service using the GitHub Copilot SDK. Once I had everything set up, I reviewed the execution logs and noticed something surprising:
In one conversation, the Agent executed a shell command, read multiple files, and downloaded a third-party MCP server from npm using npx—all without my intervention.
I hadn’t programmed any of that in advance. The model autonomously decided, in real time, to run those commands, access those files, and install that package.
That’s when it struck me: a large part of the code running in this container was generated dynamically — not by me, but by the model itself.
This is a significant shift compared to a typical web service. In a standard application, every line of code is crafted by a human, carefully reviewed, and tested before deployment. However, with an AI Agent, some behaviours unfold at runtime, meaning you can’t predict exactly what it will do beforehand.
This raises a vital question: does the container housing the AI Agent provide adequate security?
To explain this further, let’s consider an analogy.
Imagine a traditional container as an apartment in a block of flats. Each apartment has its own walls—namespaces and cgroups serve to keep things compartmentalised. Inside, it feels private.
However, all apartments share the same roof—the host Linux kernel.
Generally, this works well. But if a vulnerability is discovered in the roof—think of a kernel flaw—someone could potentially move across the roof and gain access to any other apartment in the block. This is known as a container escape.
In standard web applications, this risk is manageable as the code inside your container is predictable. An AI Agent, however, presents a different scenario: the code executing within the container is fundamentally unpredictable. Your concern isn’t an external intruder; it’s the Agent itself.
Docker clearly articulated this in their blog post Comparing Sandboxing Approaches for AI Agents:
AI Agents require a level of sandboxing that traditional shared-kernel containers simply cannot provide.
So, what is a viable solution?
Returning to the building analogy, if the issue lies with a shared roof, the answer is quite straightforward: ensure each apartment has its own roof.
You still have your apartment (the container), and the building is managed in the same way (Kubernetes). However, now you have your own ceiling above you. Even if you breach it, you would only break through your own roof—your neighbours remain untouched.
This concept encapsulates the essence of a microVM.
Koyeb has a fantastic overview titled What Is a microVM. Here’s a summary:
- It functions as a virtual machine—with its own independent guest kernel, completely isolated from the host kernel. This isolation is where the security lies.
- But it’s a trimmed-down version—only the essentials: CPU, memory, network, and block storage. No USB ports, no audio devices, no GPU passthrough.
- So it’s both fast and lightweight—offering millisecond boot times, a reduced memory footprint, and an experience close to that of containers.
In short: microVM = VM-level isolation + container-like efficiency.
It’s great to understand the advantages of microVMs, but keep in mind, Kubernetes operates with Pods and containers, not VMs. How can we connect these two frameworks?
That’s precisely the role of Kata Containers. Their slogan perfectly captures it:
“The speed of containers, the security of VMs.”
Kata acts as a bridge between Kubernetes and microVMs:
- From Kubernetes’ viewpoint, it appears as a standard Pod—scheduled, managed, and monitored just like any other.
- Internally, that Pod runs in a lightweight VM with its own kernel.
You won’t have to tweak your application code or change your CI/CD pipeline. Just instruct Kubernetes: “Run this Pod with Kata’s RuntimeClass,” and Kata will handle the rest.
On Azure Kubernetes Service (AKS), Microsoft has integrated Kata by default under the name Pod Sandboxing. The hypervisor used is Microsoft Hyper-V (not QEMU), and the RuntimeClass is named kata-vm-isolation. You create a specific node pool, and AKS configures it all automatically.
Now, let’s get practical. I developed a demo called AKS_MicroVM that serves one purpose:
To run a GitHub Copilot SDK Agent service on AKS, specifically enforced to operate within the kata-vm-isolation—a microVM sandbox.
Here’s how the architecture looks:
HTTPS request arrives
└─ AKS Node Pool (KataVmIsolation enabled)
└─ Pod (runtimeClassName: kata-vm-isolation)
└─ Dedicated Hyper-V microVM
└─ FastAPI service (Python / uvicorn)
└─ GitHubCopilotAgent
└─ Copilot CLI (Node.js)
└─ MCP servers / tools
Isolated guest kernel + seccomp + cgroup
Egress limited by NetworkPolicyFrom an external perspective, it behaves like a standard AKS Pod. Internally, however, the application operates within its own micro virtual machine, accompanied by a dedicated kernel.
The entire sample consists of these files:
app/ ← Agent service (Python)
main.py ← FastAPI endpoints
agent.py ← Copilot Agent wrapper
tools.py ← Example function tools
requirements.txt
Dockerfile ← Python 3.12 + Node 20 + Copilot CLI
k8s/ ← Kubernetes configurations
namespace.yaml
runtimeclass.yaml ← Reference (AKS auto-creates this)
secret.example.yaml ← Token placeholder
deployment.yaml ← The main file: enforces kata-vm-isolation
service.yaml
networkpolicy.yaml ← Secures ingress/egress
infra/ ← Infrastructure scripts
01-create-aks.sh ← Create the cluster
02-build-push.sh ← Build image and push to ACR
03-deploy.sh ← Deploy everythingJust three shell scripts to set up the infrastructure and six YAML files to deploy the service.
I want to highlight that this sample doesn’t simply impose a microVM and call it a day. It incorporates five layers of security:
| Concern | Resolution |
|---|---|
| Malicious code escaping the container | kata-vm-isolation → dedicated microVM with its own kernel |
| Privilege escalation within the container | runAsNonRoot + drop ALL caps + read-only filesystem + seccomp |
| Agent sending data to unauthorised endpoints | NetworkPolicy allowlist — only Copilot/GitHub/MCP egress allowed |
| Token leakage | K8s Secret injection (easily upgradeable to Key Vault via CSI) |
| Model instructing the Agent to execute risky actions | on_permission_request defaults to deny; only approved operations are allowed |
The microVM serves as the outermost defence—a form of hardware-grade isolation. But inside this barrier, there are still guards, access controls, and surveillance measures. You require all of them.
# ① Create an AKS cluster with Kata support
bash infra/01-create-aks.sh
# ② Check that the RuntimeClass is operational
kubectl get runtimeclass kata-vm-isolation
# ③ Build the image and upload it to ACR (script auto-detects your ACR)
bash infra/02-build-push.sh
# ④ Insert your GitHub Copilot token
# Edit k8s/secret.example.yaml → rename it to secret.yaml (don’t commit it!)
# ⑤ Implement everything
bash infra/03-deploy.sh
# ⑥ Access via API server proxy
kubectl proxy --port=8001After that, chat with the Agent:
curl -s -X POST \
http://localhost:8001/api/v1/namespaces/copilot-agent/services/copilot-agent:80/proxy/chat \
-H 'content-type: application/json' \
-d '{"message":"Briefly introduce Kata Containers."}'Want live output? Try the streaming endpoint:
curl -N -X POST \
http://localhost:8001/api/v1/namespaces/copilot-agent/services/copilot-agent:80/proxy/chat/stream \
-H 'content-type: application/json' \
-d '{"message":"List 3 Linux kernel hardening tips","stream":true}'Need a quick check?
kubectl -n copilot-agent exec deploy/copilot-agent -- uname -r
If the kernel version differs from that of the node — your Pod is operating under its own guest kernel, keeping it separate from the host’s. That’s your proof.
Note that kubectl port-forward is incompatible with Kata Pods. This is an easy pitfall to stumble into. While the app listener runs inside the microVM, port-forward connects to an empty sandbox netns on the host—resulting in a “connection refused” error. Use kubectl proxy instead.
Environment variable names for tokens. The Copilot CLI requires GH_TOKEN or GITHUB_TOKEN—not a custom designation. The Deployment automatically injects both from the same Secret.
A read-only filesystem necessitates emptyDir mounts. The container operates with a readOnlyRootFilesystem: true setting, but the Copilot CLI needs to write to /home/agent/.cache during startup. The Deployment mounts emptyDir volumes at .cache, .copilot, and /tmp—miss even one and the CLI might fail to launch.
Keep on_permission_request set to deny by default. The tool calls made by the Agent pass through a permission gate that defaults to deny, only allowing specified operations to proceed. Avoid changing this to approve-all in production.
To recap clearly:
① Scenario: AI Agents run model-generated, potentially untrusted code in containers
② Problem: Traditional containers share the host kernel—one escape compromises the entire node
③ Insight: We need stronger isolation than what namespaces provide
④ Solution: microVMs—each Pod gets its own dedicated guest kernel
⑤ Integration: Kata Containers brings microVM functionality to Kubernetes; AKS Pod Sandboxing makes it seamless
⑥ Implementation: The AKS_MicroVM example—six simple steps to deploy, bolstered by five levels of defence
In this era of AI Agents, a container isn’t merely a container for your application—it’s a box for uncertainty. It demands a more robust protective layer. That’s where the microVM comes into play.
Access the complete source code here: https://github.com/kinfey/Multi-AI-Agents-Cloud-Native/tree/main/code/AKS_MicroVM
For more insights, check out:
Share this content:
Discover more from Qureshi
Subscribe to get the latest posts sent to your email.