Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion docs/node-autoscaling.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ Cluster Autoscaler (dynamic workers, managed by KSail)
generates the worker config secret (`cluster-autoscaler-config`), and
manages the Talos snapshot lifecycle. Node pool configuration lives in
`ksail.prod.yaml`, not in Flux manifests.
- **Metadata isolation** — the Hetzner overlay denies pod egress to the
instance metadata service (`169.254.169.254`) with
`require-mutual-auth`. This preserves Talos/host boot-time user-data access
while preventing workloads on autoscaled nodes from reading the reusable
worker machine config from IMDS.
- **Storage architecture** — autoscaler nodes are **compute-only** (no
Hetzner volume, no Longhorn storage). Static KSail workers have
dedicated Hetzner volumes and serve as Longhorn storage nodes. Pods on
Expand All @@ -54,7 +59,9 @@ Cluster Autoscaler (dynamic workers, managed by KSail)
- `HCLOUD_CLOUD_INIT` — base64-encoded Talos worker machine config
generated by KSail.
3. The server boots Talos, applies the machine config, and joins the cluster.
4. Once the node is Ready, pending pods are scheduled.
4. Once the node is Ready, pending pods are scheduled. A prod-only Cilium
cluster-wide deny policy blocks pod egress to Hetzner IMDS
(`169.254.169.254`) so workloads cannot read the user-data after boot.

---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,12 @@ spec:
- {}
authentication:
mode: required

# Deny pod egress to Hetzner IMDS. Autoscaler-created workers receive their
# Talos worker machine config through Hetzner user-data, and that config
# contains reusable cluster join material. Keep host/Talos boot-time metadata
# access intact, but prevent workloads from reading user-data after a node
# joins the cluster.
egressDeny:

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Apply the IMDS deny to every endpoint

This egressDeny inherits the policy-level endpointSelector, which intentionally excludes every endpoint carrying k8s-app=kube-dns. The exception is cluster-wide rather than namespace-bound, so actual CoreDNS and any workload able to carry or spoof that label remain outside the metadata deny and can still reach 169.254.169.254 when their other egress policy permits it. Because that endpoint exposes reusable Talos join material, this defeats the stated security boundary. Put the IMDS deny in a separate prod-only CiliumClusterwideNetworkPolicy with endpointSelector: {} (leaving the mutual-auth CoreDNS carve-out on its original rule), and add negative coverage for both a normal pod and a kube-dns-labeled pod.

- toCIDRSet:
- cidr: 169.254.169.254/32
Loading