Skip to main content

Security architecture

Inspect 1.36

Syself Autopilot secures the machines and the control plane; you secure your workloads. Underneath both, Hetzner runs the certified hardware. So responsibility splits across layers: Hetzner runs the data centers, Syself runs the platform and ships the evidence its controls produce, and you own your workloads and your audit. Renting a certified commercial kitchen works the same way: the building carries its own inspection certificate, the operator hands you the maintenance records, and the health inspector still inspects your restaurant, not the building.

This page looks closely at the platform layer: the defenses on by default, the layers you own, and where the line sits. works through that split and the framework mappings, and the concept behind it is . Read this page first for the overview, then read the linked pages before you rely on any control in production.

The shared-responsibility line#

Most of the platform layer is on by default. The rest waits on a decision only you can make, so the platform ships none of it.

Syself secures, on by default:

  • an immutable, dm-verity sealed OS on every node
  • an enforcing AppArmor profile and RuntimeDefault seccomp on every container
  • a default-deny host firewall and API server lockdown
  • a mutual-TLS reverse tunnel with rotating certificates
  • a CIS-hardened control plane and RBAC
  • admission guardrails that stop a broken webhook from locking the control plane
  • auditd with a BSI C5 ruleset and runtime tamper-evidence

You configure:

  • NetworkPolicies (pods are default-allow on a fresh cluster)
  • Pod Security Standards (no default level is set)
  • etcd encryption at rest (opt-in)
  • OIDC and least-privilege RBAC for your users
  • log shipping to a SIEM or append-only store
  • workload image signature verification
Warning

If you assume the cluster is zero-trust and change nothing inside it, your pods are still open to each other. The zero-trust posture applies at the host layer; you extend it to your workloads.

Threat model summary#

Each row is an attacker position: what they must do to win, what stops or detects them, and what stays open. works through each in full.

Attacker position What they must do to win What stops or detects them Residual
Internet scanner Reach a service on the node's public IP Default-deny eBPF host firewall; every port allowed only for its named consumer; 6443 answers only to the control-plane load balancer; the tunnel is dialed outward from the node, so it accepts no inbound connection SSH on port 100 answers from anywhere until you add a deny policy
Compromised non-privileged workload Escape the container, load kernel code, or reach node services Enforcing AppArmor and RuntimeDefault seccomp; MODULE_SIG_FORCE rejects unsigned modules; the host firewall keeps node ports away from pod identities; CEL policies stop a webhook from locking admins out Pods are default-allow and no Pod Security level is set until you configure them
Node-level root Change the OS or persist unseen Kernel dm-verity across the sealed OS layers; the health daemon latches SealedOSTampered and NodeTampered to the Node object, so the record survives a disk wipe /var is writable, so it is tamper-evident, not sealed; recovery is a reprovision
Disk or boot-line attacker Rewrite the EFI boot line and boot a replacement image Below the boot line, dm-verity blocks every in-place edit; the base root hash is recomputable from the released image, so a swapped boot line is detectable by comparison No Secure Boot and no TPM: whoever controls the EFI partition controls that node

Layer 1: OS integrity#

Each node runs a sealed, read-only OS that cannot change at runtime. dm-verity checks every disk block against a hash tree on every read, so a tampered block fails the read. The model is keyless: authenticity comes from content-hash pinning, not from a signing key, so the node stores no key an attacker could steal. The kernel is built with MODULE_SIG_FORCE, so unsigned modules cannot load, and there is no package manager or cloud-init, so nothing can be installed at runtime. auditd runs an immutable BSI C5 ruleset. The full model, the partition layout, and the limits (no TPM, no Secure Boot) are in .

Layer 2: network and zero trust#

Every node runs directly on the public internet, so security comes from how each connection is authenticated, not from network location. Cilium's host firewall runs default-deny in eBPF, and each host port is reachable only from an explicit allow-list of identities. A Cilium policy blocks 6443 from the internet except from the control-plane load balancer. The management tunnel is dialed outward from the node over mutual TLS, so nothing can open a connection to the node from outside. Kubelet certificates rotate automatically. Cross-node pod traffic can be encrypted with WireGuard (off by default). The full story is .

Layer 3: workload security#

The platform confines every non-privileged container with a default AppArmor profile and RuntimeDefault seccomp; the rest of this layer is yours.

  • Pods are default-allow. The host firewall is default-deny for node traffic, but pod-to-pod traffic is open until you write a .
  • No default Pod Security level. Every namespace runs privileged until you .
  • Admission guardrails you cannot disable. Built-in ValidatingAdmissionPolicies run inside the API server: they stop a tenant webhook from locking admins out, protect the platform's own policies from removal, and reject network-policy rules the datapath cannot enforce. See .
  • VM isolation is available per pod as the secure RuntimeClass, on bare-metal nodes. See .

Layer 4: compliance and evidence#

The platform produces evidence continuously: the NodeTampered finding is written to the Node object (so it survives a disk wipe), and the audit streams (auditd on every node, the Kubernetes API audit log and the KubeGate audit log on the control plane) record who reached the API, who changed what, and what the OS saw. Every release ships machine-readable evidence, an SBOM with VEX triage, an OpenVEX advisory, and a CVE feed, and patches critical CVEs within 72 hours of publication; see . Shipping the audit streams to an append-only store is your responsibility; see . Framework mappings are in .

Note

Known gaps. The /var tamper baseline resets when the health daemon restarts. There is no built-in off-node log shipping. etcd encryption is opt-in. SSH on port 100 is open to the internet by default. TPM-backed measured boot is not set up. Each has a page on how to close or watch it.

Your production hardening checklist#

Segment workloads #

Add a default-deny per namespace.

Constrain pods #

Label each namespace with a level.

Encrypt secrets at rest #

Turn on .

Wire OIDC and least-privilege RBAC #

Keep users off system:masters. See .

Ship logs off-node #

Send the three audit streams to an append-only store. See .

Verify workload images #

Require signed images at admission. See .

Isolate hostile workloads #

Run untrusted code under the secure RuntimeClass. See .