← All posts

Your own environment, explained

product guide security

In the comparison the row we care most about says that on Basable every environment is a Kubernetes cluster of its own. That is a short sentence for a lot of machinery, and since it is the machinery that makes “your own environment” true, this post goes through it: what you get, where the walls are, and what you cannot do on purpose.

One cluster per environment

Each project has a preview and a live environment, and each of them is a Kubernetes cluster: its own API server, its own namespaces, service accounts, roles and custom resources. Download its kubeconfig from the editor and kubectl works as on a cluster you run yourself, and so does anything built on it, Helm included. The assistant debugs through the same cluster, with read-only commands.

Technically it is a virtual cluster, vCluster, running on a worker cluster shared with other environments: the control plane is yours, the machines underneath are shared. That sharing is what the rest of this post is about, because everything else exists to make it safe.

Walls at the kernel

Ordinary containers share the host’s kernel, so a kernel bug is a way from one container into another. Every pod in a tenant environment therefore runs in a sandbox. On our bare-metal servers that is Kata Containers: each pod gets a lightweight virtual machine with a kernel of its own. On cloud servers it is gVisor, a kernel written in user space that stands between the pod and the host. The platform sets the sandbox at admission, on every pod, including the ones you apply by hand. A pod cannot opt out, and the settings that shape the virtual machine are not yours to change.

Pods that cannot become root

Inside the sandbox, the restricted Pod Security Standard applies: no root user, no privilege escalation, every Linux capability dropped, the default seccomp profile, no host network and no host paths. This is why the assistant builds on images such as nginxinc/nginx-unprivileged instead of the stock nginx. The platform refuses a pod that does not comply rather than rewriting it, so what you apply is what runs, and a rejection shows up as a rejection.

Network: in through the gateway, out to the internet

Traffic reaches your pods from two places only: the shared gateway, which terminates HTTPS for your hostnames, and other pods in the same environment. Nothing else on the worker cluster, no other environment included, can open a connection to them. Outbound, your pods reach each other, the cluster’s DNS and the public internet. Private address ranges beyond your own environment are closed, and the cloud provider’s metadata endpoint, the usual way to steal a server’s credentials, is denied by an explicit rule that holds even if the general rule is ever widened.

Hostnames follow the same shape. You write an HTTPRoute inside your cluster, the platform mirrors it to the gateway, and a route that names a hostname belonging to another project is refused there, so nobody can claim yours.

Limits you set, enforced for everyone

The CPU, memory and storage you declare for an environment in .basable/config.yaml become a quota on its cluster, with defaults for containers that declare nothing and a cap on scratch disk, so a runaway process cannot fill the server’s disk and evict its neighbours. Two kinds of Kubernetes object are refused outright: Services of type LoadBalancer or NodePort, which would order a load balancer from the cloud provider on our account, and persistent volumes on any storage class but the sanctioned one. On a live environment that class keeps two copies of every volume on two servers; on preview, one copy, which is cheaper. A database that matters backs itself up into the environment’s bucket besides, once the environment has object storage.

Sleep

A preview nobody has touched for thirty minutes goes to sleep: its workloads stop and its control plane shrinks to its state store, so it costs nothing. A site served from the environment’s bucket keeps answering while it sleeps. The next push wakes it, and everything comes back as it was.

When you break it

Admin access includes the power to delete the parts that make the cluster work, such as its DNS or the imported gateway. We decided not to take that power away. Instead a deployment checks for them and puts them back before it continues.

What is not there yet

Two things a security team will ask about are open. We do not scan or restrict the images you pull: any public image runs, as long as it runs without root. And runtime observability, audit logs and flow logs you could read yourself, is on the list but not built. For a regulated workload, a dedicated cluster or your own cluster is the answer today.

Everything above holds whether the manifests came from the assistant or from your own kubectl apply. None of it is enforced by the assistant or by the deploy pipeline. It is enforced by the cluster, which is the only place enforcement means anything when you hold the kubeconfig.

Sign up with just your email and download the kubeconfig of your first preview: it is a real cluster, and it is yours.