This document records the security boundaries for native k3s production.
The parent migration plan defines hardening gates; this
file does not authorize broad firewall or credential changes. The executable
policy and recovery/audit procedure are in
HOST-HARDENING-RECOVERY.md and
ansible/inventories/production/hardening-policy.yml.
The three-node native k3s control plane and embedded-etcd quorum are complete.
Native Traefik is Flux-managed on .73, .41, and .42 and owns public
application traffic. Cloudflare DNS-only records include all three native
application addresses and use direct round-robin; this is not a
health-aware load balancer. The native API is reached directly at
https://169.58.143.41:6443, with k3s-api.belacca.com resolving to .41
and .42.
Native certificates use cert-manager Cloudflare DNS-01 and namespace-local Secrets. Do not make API, etcd, kubelet, overlay, or Longhorn ports public to solve an ingress or failover problem.
Native-node access is key-based and must use the dedicated
belacca-infra_ed25519 key. After access is verified on a host:
- set
PermitRootLogin prohibit-password; - set
PasswordAuthentication noandKbdInteractiveAuthentication no; - verify the effective policy with
sshd -T, not only the drop-in file; - restrict SSH with provider firewall rules or a documented administrator CIDR;
- retain a tested provider-console and native recovery path before tightening access; and
- do not infer that native production authorizes disruptive SSH or firewall changes outside a reviewed maintenance window.
The completion gate is python3 scripts/validate_hardening.py --require-runtime-evidence; it must remain failing while provider, console, or
per-host recovery evidence is absent. See the recovery runbook for the
emergency key rotation and sanitized audit procedure.
The two temporary VPS passwords supplied for onboarding were used only for key installation and must be rotated or invalidated after bootstrap hardening. Never place credentials in Ansible inventory, this repository, shell history, or repository history.
- TCP 6443 is limited to the three cluster nodes and explicitly approved operator access.
- TCP 2379-2380 is limited to native server peers for embedded etcd.
- TCP 10250 is limited to cluster peers for kubelet access.
- UDP 51820 is limited to cluster peers for the Flannel WireGuard-native overlay.
- Longhorn frontend and replica/control ports are limited to storage-node addresses.
- TCP 80/443 are public only on the intentionally exposed native Traefik
edges
.73,.41, and.42.
The absence of a health-aware load balancer is a hardening limitation, not permission to open cluster-internal services or bypass the provider firewall.
- Flux reconciles Kubernetes resources from
belacca-gitops. - SOPS-encrypted Secret manifests and the age public recipient may be stored in the public GitOps repository; only ciphertext belongs there.
- The age private key is installed only as the Flux decryption Secret in
flux-systemand in independent offline backups. It must not be committed, copied into this infrastructure repository, or printed in CI/operator logs. - This infrastructure repository contains host configuration and network posture, not passwords, kubeconfigs, join tokens, private keys, OAuth credentials, or application data.
Rotate application credentials without committing plaintext values. Preserve Git history, native Longhorn state, and the post-cutover external-backup/failure-drill plan.