A practical look at container escape risks, public-IP scanning, and how Firecracker microVMs on Krova Cloud changed how I think about cloud infrastructure security.
The moment I stopped trusting my own stack
A few months ago, I got that Slack message nobody wants:
"One of our containers is acting weird. High CPU. Unknown process. Can you check?"
It turned out to be a cryptominer. Not because someone hacked our app. Not because we leaked secrets. But because another tenant on the same host had a vulnerable container, and the attacker escaped into the shared kernel.
We didn't do anything wrong. We followed the playbook: updated images, minimal privileges, read-only root filesystems. But we were still sitting on the same kernel as everyone else.
That incident made me ask a question I'd never seriously considered:
What if the real cloud security problem isn't our configuration - it's the architecture underneath?
This post is the answer I found. It's about why I started thinking of every app as its own fortress, and how platforms like Krova Cloud make that practical.
The two lies we tell ourselves about cloud security
Lie #1: "Containers are isolated enough"
Containers isolate processes. They don't isolate kernels.
Every container on a host shares the same Linux kernel. That's by design — it's why containers are fast and lightweight. But it also means a single kernel vulnerability can compromise every container on that machine.
Recent CVEs like Dirty Pipe, CVE-2022-0847, and privilege-escalation chains have shown this repeatedly. You don't need a zero-day. You need one kernel bug and one noisy neighbor.
┌─────────────────────────────────────┐
│ Host Kernel │ ← one shared kernel
├─────────────┬─────────────┬─────────┤
│ Container 1 │ Container 2 │ Your │
│ (tenant) │ (tenant) │ app │
└─────────────┴─────────────┴─────────┘
If an attacker breaks out of any container, they can potentially touch yours.
Lie #2: "A public IP is just how servers work"
The second lie is that every server needs a public IP address.
It doesn't. But VPS providers hand them out by default because it's convenient. The problem? That IP is now on the internet 24/7, being scanned, brute-forced, and probed by bots.
Within minutes of launching a typical VPS, you'll see:
SSH brute-force attempts
Port scans on every service
Automated exploit attempts
Your security model becomes: "I have a public address, and I hope my firewall rules are perfect."
Spoiler: they usually aren't.
What if isolation meant a real kernel?
This is where microVMs come in.
A microVM is a lightweight virtual machine. Unlike a container, each microVM boots its own kernel. Unlike a traditional VM, it starts in milliseconds - fast enough to spin up and tear down like a container.
The technology behind this is Firecracker, the same isolation engine AWS uses for Lambda and Fargate. It's designed for:
Strong isolation (full VM boundary)
Fast startup (sub-second boot)
Low overhead (minimal resource usage)
High density (many VMs on one host)
┌─────────────────────────────────────────────┐
│ Host Hardware │
├─────────────────┬───────────────────────────┤
│ VM 1 │ VM 2 │ Your │
│ own kernel │ own kernel │ app │
└─────────────────┴───────────────┴──────────┘
Each VM has its own kernel. A kernel bug in one can't reach another.
How Krova Cloud turns microVMs into a security model
That's the theory. Krova Cloud is the practice.
Krova Cloud calls its microVMs Cubes. Each Cube is a Firecracker microVM with a few security-first design choices that directly solve the problems I mentioned:

But the part that matters most? It's not just secure , it's usable.
Spinning up a Cube: from zero to root in seconds
Here's what provisioning looks like with the Krova CLI:
Bash
`# Install the CLI
npm i -g @krovacloud/cli
Create a Cube
krova cubes create web-1 \
--cpu 2 \
--ram 4 \
--disk 40 \
--image ubuntu-24.04
SSH in with full root access
krova ssh web-1
root@web-1:~#`
No VPCs. No security groups. No IAM roles. No launch templates. Just a real VM, isolated by hardware virtualization, booted in under a second.
If you prefer code, the REST API is just as simple:
Bash
curl -X POST https://krova.cloud/api/v1/spaces/$SPACE/cubes \
-H "X-API-KEY: $KROVA_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"name": "web-1",
"image": "ubuntu-24.04",
"resources": { "vcpu": 2, "ramGb": 4, "diskGb": 40 },
"sshPublicKey": "ssh-ed25519 AAAA...",
"region": "eu-central"
}'
Same result: one isolated Cube, own kernel, no public IP.
What "no public IP" actually means for security
This is the part that took me a while to fully appreciate.
When a Cube has no public IP, it literally doesn't exist on the public internet. There's no address to scan. No port to probe. No brute-force target.
Inbound traffic only reaches your Cube through Krova Cloud's managed ingress layer:
Web traffic enters through a TLS-terminated edge
Your custom domain points to that edge, not to your Cube
The Cube origin stays hidden
Non-web services use explicit port mappings with IP allowlists
text
Internet → Krova Ingress (TLS, DDoS-mitigated)
↓
Hidden origin
↓
Your Cube (private IP)
Compare that to a standard VPS:
text
Internet → Your public IP
↓
Your server (ssh, db, api all exposed)
The difference is night and day. With no public IP, the attacker can't attack what they can't find.
Mapping Krova's design to real cloud security principles
Let's translate the Cube architecture into the security fundamentals we all know:
- Defense in depth A Cube isn't just one layer of isolation. It's several:
Hardware virtualization via KVM
Separate kernel per VM
Jailer sandbox around the hypervisor
No public IP
Stateful default-deny firewall
IP-allowlisted port mappings
Managed TLS ingress
That's defense in depth without you configuring any of it.
- Least privilege By default, nothing is reachable. You have to explicitly open a port. And when you do, you can lock it to a specific IP range.
Bash
# Example: open SSH only from your office IP
krova ports add web-1 \
--protocol tcp \
--port 22 \
--allowed-ips 203.0.113.0/24
This is least privilege applied to networking.
- Attack surface reduction No public IP means no SSH brute-forcing. No open database ports scanned by Shodan. No accidental exposure because someone misconfigured a security group.
The attack surface is reduced by architecture, not by hoping humans never make mistakes.
- Isolation of failure If one Cube is compromised, the blast radius is that Cube. Not the host. Not other tenants. Not your entire stack.
When microVMs make sense (and when they don't)
I'm not here to say containers are dead. They're not. But I think we overuse them for workloads that need real isolation.
MicroVMs are a great fit for:
User-submitted code (judge0-style platforms, coding interviews)
AI agents that run arbitrary shell commands
CI/CD runners that should start clean every time
Multi-tenant SaaS where each customer needs isolation
Databases and stateful services that benefit from a real kernel
Anything handling untrusted data
Containers are still fine for:
Internal microservices with trusted code
Development environments
Workloads where density and speed matter more than isolation
Teams already heavily invested in Kubernetes
The key is choosing the right isolation model for the risk.
A cloud security checklist for 2025
Whether you use Krova Cloud, AWS, Azure, or a mix, here's my current checklist:
Markdown
□ Assume shared kernels can be compromised — isolate high-risk workloads
□ Avoid public IPs unless absolutely necessary
□ Use IP allowlists for any administrative access
□ Enable MFA for all cloud consoles and SSH jump hosts
□ Rotate access keys every 90 days (or use temporary credentials)
□ Block public access on all storage buckets by default
□ Scan repos for leaked secrets before every merge
□ Centralize logs and set alerts for root login, IAM changes, and public exposure
□ Test your incident response plan before you need it
□ Review your architecture choices as often as your code
The last one is the hardest — and the most important.
Why this changed how I build
Before the cryptominer incident, I thought cloud security was about configuration: the right IAM policies, the right firewall rules, the right patches.
I still think those matter. But I now believe the foundation matters more.
If your architecture assumes a shared kernel and a public IP, you're asking your configuration to be perfect forever. That's a losing game.
If your architecture gives every workload its own kernel and hides it from the public internet, you've made security the default. That's a much better place to operate from.
That's why I started using Krova Cloud for workloads where isolation matters. Not because it's a magic bullet, but because it aligns the default architecture with good security hygiene.
Try it yourself
If you're curious, you can spin up a Cube for free (signup doesn't require a card, and the first $5 top-up doubles to $10):
Bash
npm i -g @krovacloud/cli
krova signup
krova cubes create security-test --cpu 1 --ram 2 --disk 20 --image ubuntu-24.04
krova ssh security-test
Once inside, run ss -tlnp and notice something beautiful: there are no public listening ports. Your server exists, but it's invisible to the internet.
Final thoughts
Cloud infrastructure security isn't just about tools and checklists. It's about architecture.
Containers gave us speed. microVMs give us speed and isolation.
Platforms like Krova Cloud make that isolation practical for everyday developers. And in a world where kernel bugs and automated scanning are constants, I think that's worth paying attention to.
What's your take? Are you still comfortable with shared kernels for sensitive workloads? Or are you already exploring microVMs and Firecracker? Drop a comment — I'd love to hear what's working for you.
Resources
Krova Cloud
Krova Cloud Security
Firecracker microVMs
AWS Lambda under the hood
NIST SP 800-190: Application Container Security Guide
Thanks for reading.
If you found this helpful, hit the ❤️ and follow for more cloud security and infrastructure posts.
Top comments (0)