Security Model#
This page describes the security measures in place across the cluster.
Authentication and access control#
SSH access#
All nodes use key-based SSH authentication only (password auth is disabled).
A dedicated
ansibleuser is created on each node with passwordless sudo.The SSH keypair is stored in
pub_keys/ansible_rsa.pub(public key only in Git).The private key lives on the operator’s workstation and is mounted into the devcontainer via a Docker volume.
Kubernetes RBAC#
The control plane uses the default K3s RBAC configuration.
Headlamp has a dedicated
headlamp-adminServiceAccount bound tocluster-adminwith a long-lived token Secret for dashboard access.ArgoCD has the
kubernetesAppProject withsourceReposrestricted to the project’s GitHub repo and trusted Helm chart registries.
Service authentication#
Service |
Auth method |
Notes |
|---|---|---|
ArgoCD |
Username/password |
bcrypt hash in |
Grafana |
OAuth (GitHub) |
via oauth2-proxy + nginx ingress |
Longhorn |
OAuth (GitHub) |
via oauth2-proxy + nginx ingress |
Headlamp |
OAuth (GitHub) |
via oauth2-proxy + nginx ingress |
Open WebUI |
OAuth (GitHub) |
via oauth2-proxy + nginx ingress |
Echo |
None (intentional) |
Public test service |
RKLlama |
None (intentional) |
Internal LLM API (fronted by Open WebUI) |
See Set Up OAuth Authentication for how to configure OAuth.
Secrets management#
Sealed Secrets#
Sensitive values (API tokens, tunnel credentials, OAuth client secrets) are
encrypted using Sealed Secrets and
stored in Git as SealedSecret resources. Only the cluster’s sealed-secrets
controller can decrypt them.
Current SealedSecrets:
kubernetes-services/additions/cloudflared/tunnel-secret.yaml— Cloudflare tunnel tokenkubernetes-services/additions/cert-manager/templates/cloudflare-api-token-secret.yaml— DNS API tokenkubernetes-services/additions/oauth2-proxy/oauth2-proxy-secret.yaml— OAuth client credentials
Admin password#
The admin-auth Kubernetes secret is created manually during bootstrap (see
Bootstrap the Cluster). It stores htpasswd credentials used by
Grafana.
Pod Security Standards#
Security contexts are applied at the workload level. See Security Hardening for a detailed breakdown of which workloads run as non-root, which have read-only root filesystems, and which require privileged access.
Container image pinning#
All container images are pinned to specific version tags. Renovate bot monitors for updates and raises PRs automatically. See Security Hardening for the full policy.
Network security#
Control plane taint#
In multi-node clusters, the control plane node has a NoSchedule taint. No regular
workloads run on it — only K3s system components (CoreDNS, metrics-server, etcd,
kube-proxy). For single-node clusters the taint is skipped so all workloads can schedule.
Cloudflare protection#
Services exposed via the Cloudflare tunnel benefit from:
WAF — Web Application Firewall with managed rulesets
DDoS protection — automatic layer 3/4/7 mitigation
Bot management — challenge suspicious traffic
Rate limiting — configurable per-hostname rules
No inbound firewall ports#
The Cloudflare tunnel uses an outbound-only connection from the cloudflared pod.
No inbound ports need to be opened on your router for public-facing services.
LAN isolation#
LAN-only services (ArgoCD, Grafana, Longhorn, Headlamp) use grey-cloud DNS records pointing to private RFC-1918 IP addresses. They are unreachable from outside the local network.
NetworkPolicies#
NetworkPolicies are not deployed by default. See Network Policies for the rationale and guidance on implementing them if needed.
TLS everywhere#
All ingress endpoints use TLS certificates from Let’s Encrypt (production CA):
Certificates are automatically issued and renewed by cert-manager
DNS-01 validation via Cloudflare API (works for LAN-only services too)
HSTS headers are set by ingress-nginx by default
ArgoCD uses TLS passthrough (handles its own certificate)
Recommendations#
Enable OAuth — replace basic-auth with GitHub OAuth via oauth2-proxy.
Rotate SealedSecrets periodically — re-seal with fresh values.
Back up the sealed-secrets key — without it, a cluster rebuild requires re-creating all secrets.
Keep nodes updated —
unattended-upgradeshandles security patches automatically.Monitor for alerts — Prometheus Alertmanager captures security-relevant events.
Review the production checklist — see Production Readiness Checklist.