Single-node k3s cluster beveiligen op een VPS
Beveilig uw k3s cluster tegen open poorten zoals 6443 en 10250. Leer hoe u kubeconfig rechten beperkt, NodePorts afschermt en privileged pods blokkeert voor een veilige VPS setup.
Wat een single-node k3s-cluster op de eerste dag blootstelt
Een single-node k3s-cluster op een publieke VPS is de dag nadat de one-line installer is voltooid op vijf specifieke punten blootgesteld: de Kubernetes API-server op TCP 6443, de kubelet op TCP 10250, het kubeconfig-bestand op de schijf, het NodePort-bereik dat uw firewall niet kan zien, en elke pod die mag vragen om privileged of hostPath. Voor elk punt is er een oplossing die slechts enkele minuten in beslag neemt. Deze handleiding gaat ervan uit dat k3s al draait; als dat niet het geval is, begin dan met een single-node k3s-installatie op een VPS en keer daarna terug.
Bekijk wat er luistert voordat u wijzigingen aanbrengt.
sudo ss -tulpn | grep -E '6443|10250|10256|8472'Een standaardinstallatie toont 6443 (de API-server), 10250 (de kubelet), 10256 (de kube-proxy health check) en 8472/udp (de flannel-overlay, die gebruikmaakt van VXLAN, virtual extensible LAN). k3s bindt standaard aan 0.0.0.0, waardoor elk van deze poorten op uw publieke adres luistert en niet alleen op localhost.
Waarom poort 6443 het hele cluster is
Alles wat met beheerdersrechten kan authenticeren op poort 6443 kan een pod aanmaken, en een pod kan root-rechten op de host verkrijgen. Poort 6443 is de toegangspoort tot de machine.
Een open poort 6443 betekent niet direct een geslaagde inbreuk, omdat Kubernetes geen wachtwoorden accepteert. Het vereist een clientcertificaat of een bearer token. Twee zaken blijven echter waar.
Ten eerste beantwoordt de API-server sommige verzoeken zonder enige vorm van authenticatie. De standaard Kubernetes RBAC (role-based access control) koppelt de groep system:unauthenticated aan een rol genaamd system:public-info-viewer, die /version, /healthz, /livez en /readyz toestaat. Vanaf een andere machine:
curl -sk https://YOUR_SERVER_IP:6443/versionDit retourneert uw exacte Kubernetes-versie, wat de input is voor een CVE (common vulnerabilities and exposures) zoekopdracht en de reden waarom een scanner besluit dat uw server interessant is. Alles voorbij die paden wordt geweigerd, en de weigering identificeert u:
forbidden: User "system:anonymous" cannot get path "/api"Ten tweede is elke bug in de API-server op afstand bereikbaar zolang die poort openstaat. Patchen is vanaf dat moment niet langer optioneel.
De goedkope oplossing is een firewallregel. ufw heeft hier meer dan één regel nodig, omdat k3s clusterverkeer via dezelfde kernel routeert.
sudo ufw default deny incoming
sudo ufw allow OpenSSH
sudo ufw allow from 203.0.113.10 to any port 6443 proto tcp
sudo ufw allow from 10.42.0.0/16 to any
sudo ufw allow from 10.43.0.0/16 to any
sudo ufw enableDe laatste twee regels komen rechtstreeks uit de k3s-documentatie. 10.42.0.0/16 is het standaard pod-netwerk en 10.43.0.0/16 is het standaard service-netwerk; zonder deze regels blokkeert ufw het interne clusterverkeer, waardoor pods de API-server en elkaar niet meer kunnen bereiken. Het k3s-voorbeeld staat poort 6443 toe vanaf elke locatie; het vervangen hiervan door uw eigen adres is de aanpassing die het waard is om door te voeren. Als u niet bekend bent met ufw, behandelt de basis van de ufw-firewall voor een VPS de standaardbeleidsregels waar dit van afhankelijk is.
De k3s-documentatie is duidelijk over de overlay-poort: "De VXLAN-poort op nodes mag niet worden blootgesteld aan de wereld, omdat dit uw clusternetwerk toegankelijk maakt voor iedereen." Een standaard 'deny'-beleid voor inkomend verkeer regelt dit zonder de poort expliciet te benoemen.
De robuustere oplossing is om de API helemaal niet meer via het publieke adres te benaderen en in plaats daarvan een VPN of mesh-adres te gebruiken. Het servercertificaat moet het adres bevatten waarmee u verbinding maakt, dus voeg dit toe als een SAN (subject alternative name) in /etc/rancher/k3s/config.yaml:
tls-san:
- 10.8.0.1
- k3s.example.com
secrets-encryption: truesudo systemctl restart k3s
sudo k3s secrets-encrypt statussecrets-encryption: true versleutelt Secret-objecten in de datastore. De k3s-documentatie merkt op dat "Secrets-encryption niet kan worden ingeschakeld op een bestaande server zonder deze te herstarten", en Secrets die vóór de wijziging zijn geschreven, behouden hun oude vorm totdat u sudo k3s secrets-encrypt reencrypt uitvoert. Wees u bewust van wat dit oplevert. Het beschermt een datastore-bestand dat uit een back-up is gekopieerd. Het doet niets tegen iemand die met de API-server kan communiceren, omdat de API-server Secrets ontsleutelt voor iedereen die ze mag lezen. Datzelfde onderscheid geldt voor elke zelfgehoste secret store; daarom besteedt een hardening-sessie voor Vaultwarden de aandacht aan het admin-token en het back-upbestand in plaats van aan de versleuteling zelf.
Waarom de kubelet op poort 10250 van belang is
De kubelet is de agent die containers start. De API op poort 10250 geeft een overzicht van pods en voert commando's uit binnen deze pods. Een kubelet die anonieme verzoeken accepteert, fungeert als een remote shell voor elke workload op de machine.
Controleer uw configuratie:
curl -sk https://127.0.0.1:10250/pods | head -c 60Een actuele k3s antwoordt met Unauthorized, omdat de kubelet de API-server vraagt om elke aanroeper te authenticeren en autoriseren. Als er in plaats daarvan een JSON-lijst met pods wordt geretourneerd, staat anonieme toegang aan. Iedereen die poort 10250 kan bereiken, kan dan gegevens lezen uit uw containers en commando's uitvoeren.
Sluit deze poort in ieder geval af voor extern verkeer. Op een single-node setup is de enige client van de kubelet het control plane op dezelfde machine. Dit verkeer verloopt via de loopback-interface, die door ufw standaard wordt geaccepteerd. Het blokkeren van 10250 voor internetverkeer heeft geen negatieve gevolgen. Als u hier bent beland vanwege een defecte kubectl top of een metrics-server die niet wil werken, vindt u de oorzaken verzameld in fouten bij kubelet poort 10250.
Uw kubeconfig is een cluster-beheerdersreferentie
k3s schrijft /etc/rancher/k3s/k3s.yaml met root als eigenaar en modus 600. De documentatie vermeldt de consequentie van het wijzigen hiervan: "Het kubeconfig-bestand is eigendom van root en wordt geschreven met een standaardmodus van 600. Het wijzigen van de modus naar 644 zorgt ervoor dat het gelezen kan worden door andere gebruikers zonder privileges op de host."
Lees dit als volgt: modus 644 maakt van elk lokaal account een cluster-beheerder. Veel handleidingen suggereren precies dit, meestal als --write-kubeconfig-mode 644, zodat kubectl werkt zonder sudo. Dit werkt door de beheerdersreferentie aan iedereen met een shell te overhandigen.
Kopieer het bestand in plaats daarvan naar één gebruiker.
mkdir -p ~/.kube
sudo install -o "$USER" -g "$USER" -m 600 /etc/rancher/k3s/k3s.yaml ~/.kube/config
kubectl get nodesBevestig daarna dat het origineel nog steeds goed beveiligd is:
stat -c '%a %U:%G' /etc/rancher/k3s/k3s.yaml600 root:root is het antwoord dat u zoekt. Dat bestand bevat een clientcertificaat voor een lid van system:masters, de groep die door de API-server onvoorwaardelijk wordt vertrouwd, waardoor RBAC-regels er nooit voor worden geraadpleegd. Kubernetes heeft geen lijst voor het intrekken van certificaten, wat betekent dat een gelekte kopie geldig blijft totdat u de certificaatautoriteit van het cluster roteert. Behandel het als een SSH private key en houd het aantal accounts dat erbij kan klein; dit is hetzelfde argument als gebruikersaccounts met minimale privileges op een VPS.
Uw firewall ziet geen NodePort-verkeer
Een type: NodePort-service opent een poort tussen 30000 en 32767 op elk adres dat de node bezit, inclusief het publieke adres. Een type: LoadBalancer-service gaat bij k3s nog een stap verder: ServiceLB, de meegeleverde load balancer, plant per service een kleine pod in kube-system die de servicepoort direct op de host claimt.
kubectl -n kube-system get pods | grep svclb
sudo ss -tulpn | grep -E ':3[0-2][0-9]{3}'Nu het onderdeel dat mensen vaak verrast. Blokkeer die poort met ufw en deze blijft antwoorden.
sudo ufw deny 30080/tcp
curl http://YOUR_SERVER_IP:30080De pagina laadt nog steeds, vanwege de route die het pakket aflegt. kube-proxy schrijft DNAT-regels (destination network address translation) naar de PREROUTING-chain van de nat-tabel, en PREROUTING wordt uitgevoerd voordat er een filterbeslissing wordt genomen. De bestemming wordt een pod-adres, wat niet de host is, dus de kernel stuurt het pakket door naar de FORWARD-chain en nooit via INPUT. De regels van ufw bevinden zich in INPUT. Het pakket komt ze nooit tegen. De volgorde van de sprongen is zichtbaar:
sudo iptables -S PREROUTING -t nat | head
sudo iptables -S FORWARD | headKUBE-SERVICES staat bovenaan in PREROUTING, en de Kubernetes-sprongen in FORWARD staan boven de eigen chains van ufw. Dit is hetzelfde mechanisme waardoor Docker poorten publiceert langs ufw heen, en de antwoorden zijn dezelfde.
- Filter bij de netwerkfirewall van uw provider. Deze draait voor de machine en geeft niet om hoe uw kernel routeert.
- Sla NodePort en LoadBalancer over. Laat services op
ClusterIPstaan en bereik ze metkubectl port-forwardvia de SSH-sessie die u al heeft. - Stel één ingress bloot op 80 en 443, en niets anders.
- Beperk het bereik met
service-node-port-rangeonderkube-apiserver-arg, zodat een per ongeluk geopende NodePort ergens terechtkomt waar u toezicht op houdt.
ufw is nog steeds nuttig om te draaien. Het beheert verkeer dat gericht is aan de host zelf, zoals SSH en de API-server. Het controleert simpelweg geen pod-verkeer, en verwachten dat het dit wel doet, is de reden dat een database uiteindelijk bereikbaar kan zijn.
Een pod met hostPath of privileged is root op uw VPS
Containers zijn gewone processen op uw kernel met een beperkt overzicht daarvan. Verschillende pod-velden heffen die beperking op.
securityContext.privileged: truegeeft de container alle Linux-capabilities en toegang tot host-apparaten.hostPathkoppelt een host-directory aan de pod. Een pod die/read-write koppelt, kan een key toevoegen aan/root/.ssh/authorized_keys.hostPID: trueplaatst de container in de host-proces-namespace, waarnsentertegen PID 1 een host-shell opent.hostNetwork: trueplaatst de container op de host-netwerkstack, waar deze host-poorten kan binden en services op loopback kan bereiken.
De vraag "wie kan hier pods aanmaken" is dus gelijk aan "wie is root op deze VPS". Elke ServiceAccount met create op pods in een willekeurige namespace is gelijk aan root, tenzij iets de pod eerst weigert.
Dat "iets" is Pod Security admission, ingebouwd in de API server. De snelle methode is een label per namespace; dit vereist geen herstart.
kubectl label namespace default \
pod-security.kubernetes.io/enforce=baseline \
pod-security.kubernetes.io/enforce-version=latest \
pod-security.kubernetes.io/warn=restrictedbaseline weigert alle vier bovenstaande velden. restricted gaat verder en vereist een non-root gebruiker, een seccomp (secure computing mode) profiel, geen privilege escalation en capabilities beperkt tot ALL, wat veel gepubliceerde charts onbruikbaar maakt. Door baseline af te dwingen terwijl u alleen waarschuwt voor restricted, kunt u zien wat er zou breken voordat u het definitief doorvoert.
Bewijs dat het werkt:
kubectl apply -f - <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: pstest
spec:
containers:
- name: app
image: busybox
command: ["sleep", "60"]
securityContext:
privileged: true
EOFDe API server weigert dit en geeft aan welk veld werd geweigerd:
Error from server (Forbidden): error when creating "STDIN": pods "pstest" is forbidden: violates PodSecurity "baseline:latest": privileged (container "app" must not set securityContext.privileged=true)Voor een cluster-brede standaardinstelling in plaats van een label op elke namespace, documenteert k3s een admission-configuratiebestand op /var/lib/rancher/k3s/server/psa.yaml:
apiVersion: apiserver.config.k8s.io/v1
kind: AdmissionConfiguration
plugins:
- name: PodSecurity
configuration:
apiVersion: pod-security.admission.config.k8s.io/v1beta1
kind: PodSecurityConfiguration
defaults:
enforce: "baseline"
enforce-version: "latest"
warn: "restricted"
warn-version: "latest"
exemptions:
namespaces: [kube-system]Verwijs de API server hiernaar in /etc/rancher/k3s/config.yaml en herstart vervolgens k3s:
kube-apiserver-arg:
- 'admission-control-config-file=/var/lib/rancher/k3s/server/psa.yaml'De kube-system vrijstelling is niet optioneel. De eigen ServiceLB-pods van k3s claimen host-poorten, wat baseline verbiedt. Als u kube-system uit de lijst weglaat, worden deze pods geweigerd zodra ze opnieuw worden aangemaakt. Houd een tweede SSH-sessie open wanneer u k3s herstart na een wijziging in de admission-instellingen.
Een extra tip: k3s wordt geleverd met een network policy controller die standaard is ingeschakeld, waardoor NetworkPolicy-objecten direct effect hebben op dit cluster zonder extra installaties. Dit geldt niet voor elke Kubernetes-distributie, en het is het instrument om te voorkomen dat een gecompromitteerde pod de rest van het cluster bereikt.
Verwijder de meegeleverde componenten die u niet gebruikt
Het installatieprogramma implementeert een set add-ons. Elke add-on voegt een listener en een extra onderdeel toe dat gepatcht moet worden. --disable accepteert deze waarden: coredns, servicelb, traefik, local-storage, metrics-server, runtimes.
Behoud coredns. Niets in het cluster kan zonder dit onderdeel namen omzetten. De rest is optioneel. In /etc/rancher/k3s/config.yaml:
disable:
- traefik
- servicelb
disable-helm-controller: truesudo systemctl restart k3s
kubectl get pods -Ak3s verwijdert componenten die u uitschakelt, waardoor de traefik-pods en de svclb--pods automatisch verdwijnen. Wees u eerst bewust van de gevolgen. Als servicelb is verwijderd, blijft elke type: LoadBalancer-service voor altijd op <pending> staan, omdat niets er een adres aan toewijst. Zonder traefik is er geen ingress-controller, waardoor Ingress-objecten helemaal niets doen. Schakel deze uit wanneer u verkeer op een andere manier afhandelt, zoals via een reverse proxy op de host, en laat ze ongemoeid wanneer u ze wel gebruikt. disable-helm-controller: true verwijdert de controller die HelmChart-resources monitort; dit is een bevoorrechte component die u niet gebruikt als u helm zelf beheert.
Stoppen met het automatisch koppelen van het standaard ServiceAccount-token
Elke pod krijgt een ServiceAccount-token op /var/run/secrets/kubernetes.io/serviceaccount/token, tenzij u anders aangeeft. Het default ServiceAccount heeft geen RBAC-rechten, dus het token alleen bereikt weinig. Wat het een aanvaller in een gecompromitteerde container wel geeft, is een geldig credential en een bereikbare API-server; dit is de eerste stap in de meeste beschrijvingen van cluster-escalatie.
De k3s hardening-handleiding schakelt dit per namespace uit:
kubectl patch serviceaccount --namespace default default --patch '{"automountServiceAccountToken": false}'
kubectl patch serviceaccount --namespace kube-node-lease default --patch '{"automountServiceAccountToken": false}'
kubectl patch serviceaccount --namespace kube-public default --patch '{"automountServiceAccountToken": false}'Controleer of dit is verwerkt. Geef de pod eerst een paar seconden de tijd om te starten.
kubectl run t --image=busybox --restart=Never --command -- sleep 30
kubectl exec t -- ls /var/run/secrets/kubernetes.io/serviceaccountHet pad is verdwenen, dus ls geeft No such file or directory weer. Een workload die daadwerkelijk API-toegang nodig heeft, stelt automountServiceAccountToken: true in de eigen pod-spec in, zodat niets permanent wordt buitengesloten. Dit is op zichzelf een kleine winst. De grotere winst is het niet toekennen van een ServiceAccount met echte rechten aan een workload, en u kunt zien wat een token momenteel waard is:
kubectl auth can-i --list --as=system:serviceaccount:default:defaultResourcelimieten, zodat één pod niet het hele cluster platlegt
Op een enkele node delen het control plane en uw workloads dezelfde kernel en dezelfde pool met geheugen. Een pod die geheugen lekt, sterft niet altijd alleen. De OOM (out of memory) killer van de kernel kiest zijn slachtoffer op basis van een score die zwaarder weegt bij grote processen. Omdat k3s een groot, langlopend proces is, kan het cluster in plaats van de pod verdwijnen. Niets herstart daarna uw workloads, omdat het proces dat workloads herstart, zelf is gestopt.
Een LimitRange vult limieten in voor pods waarvoor er geen zijn ingesteld:
apiVersion: v1
kind: LimitRange
metadata:
name: defaults
namespace: default
spec:
limits:
- type: Container
default:
cpu: 500m
memory: 512Mi
defaultRequest:
cpu: 50m
memory: 128MiEen ResourceQuota begrenst wat de gehele namespace kan claimen:
apiVersion: v1
kind: ResourceQuota
metadata:
name: cap
namespace: default
spec:
hard:
limits.cpu: "3"
limits.memory: 3Gi
pods: "20"Reserveer vervolgens ruimte voor k3s zelf in /etc/rancher/k3s/config.yaml:
kubelet-arg:
- 'system-reserved=cpu=250m,memory=512Mi'Het verschil is op twee plaatsen zichtbaar. Een container die wordt beëindigd omdat deze de eigen limiet overschrijdt, rapporteert Reason: OOMKilled onder Last State in kubectl describe pod, en de rest van de node blijft functioneren. Een node die volledig zonder geheugen kwam te zitten, laat een Killed process-regel achter in dmesg en neemt meestal naburige processen mee. Het eerste is uw limiet die zijn werk doet. Het tweede is wat limieten juist moeten voorkomen.
Manifests scannen in CI en het k3s-cluster volgens een schema
Scannen moet op twee plekken gebeuren, aangezien ze verschillende problemen detecteren. Installeer eerst Trivy. Het project brengt bij elke release een Debian-pakket uit. Versie 0.74.0 was actueel in augustus 2026; controleer de releases-pagina op een nieuwere versie voordat u dit vastlegt in uw automatisering.
sudo apt-get install -y wget
wget -q https://github.com/aquasecurity/trivy/releases/download/v0.74.0/trivy_0.74.0_Linux-64bit.deb
sudo dpkg -i trivy_0.74.0_Linux-64bit.deb
trivy --versionDe eerste plek is in uw manifests, voordat deze het cluster bereiken.
trivy fs --scanners misconfig --severity HIGH,CRITICAL --exit-code 1 ./deploy--exit-code 1 laat de CI-taak (continuous integration) falen bij een bevinding. Elk resultaat benoemt het falende veld en de ernst ervan, zodat een privileged: true die u niet wilde committen de build stopt in plaats van de API-server te bereiken. Een bevinding die u besluit te accepteren, plaatst u in een .trivyignore-bestand; hiermee blijft die beslissing in git bewaard naast het manifest dat de melding veroorzaakte.
De tweede plek is het draaiende cluster, volgens een schema.
trivy k8s --compliance=k8s-cis-1.23 --report summaryEen eerlijke opmerking over dat commando: trivy k8s implementeert een node-collector-pod die host-toegang nodig heeft om instellingen op node-niveau te inspecteren. Op een cluster waar u net bent begonnen met het weigeren van geprivilegieerde pods, is dit iets om op te merken in plaats van te omzeilen. trivy k8s --report summary --disable-node-collector slaat de collector over en verliest daarmee de controles op node-niveau.
kube-bench dekt de host-kant: bestandsrechten en proces-vlaggen, waar het merendeel van de CIS (Center for Internet Security) benchmark zich bevindt. Het bevat een k3s-profiel. Neem het upstream Job-manifest en pas dit aan.
curl -sfL -o kube-bench-job.yaml https://raw.githubusercontent.com/aquasecurity/kube-bench/main/job.yamlWijzig het container-commando naar ["kube-bench", "--benchmark", "k3s-cis-1.7"] en vervang de /etc/kubernetes- en /var/lib/etcd-mounts door /etc/rancher en /var/lib/rancher, omdat k3s zijn bestanden daar bewaart. Vervolgens:
kubectl apply -f kube-bench-job.yaml
kubectl logs -l app=kube-bench --tail=-1Let op wat die Job is: hostPID: true plus host-directory-mounts; dit is precies de pod-vorm die u een sectie geleden begon te weigeren. Voer het uit in de vrijgestelde kube-system-namespace, lees de uitvoer en voer daarna kubectl delete job kube-bench uit. Een scanner die geprivilegieerd moet zijn, is geen reden om te stoppen met het verbieden van geprivilegieerde workloads.
De inhoud van images is een aparte kwestie. trivy image ghcr.io/example/app:1.4 leest de pakketdatabase in een image en somt op wat bekend staat als kwetsbaar; dit is dezelfde taak als wanneer u uw server controleert op bekende CVE's.
Nu het eerlijke deel over de uitvoer van scanners: een hobby-cluster met één node zal voor een lange lijst met CIS-controles falen, en de meeste van die fouten zijn zowel correct als irrelevant voor u. De benchmark is geschreven voor een multi-node, multi-tenant cluster: etcd op aparte hosts, audit-logs die naar een andere machine worden gestuurd, een aparte certificate authority voor de kubelet, en admission-plugins voor een compliance-regime waar u niet aan onderworpen bent. k3s voert het control plane bewust uit als één proces met één configuratiebestand, dus controles die de rechten van een kube-scheduler-manifestbestand verifiëren, kunnen niet slagen omdat zo'n bestand niet bestaat.
Lees de foutmeldingen in deze volgorde en stop wanneer de waarde afneemt: bestandsmodi en eigenaarschap onder /etc/rancher en /var/lib/rancher, alles wat anonieme of niet-geauthenticeerde toegang noemt, alles wat rapporteert dat een component is gebonden aan 0.0.0.0, en elke container die draait als UID 0 zonder reden. De rest kan wachten op een tweede node of een tweede persoon met toegang. Een rapport van honderd regels dat u negeert, is minder waard dan een rapport van vijf regels waar u actie op onderneemt.
Volgorde voor het beveiligen van een k3s single-node
- Stel het standaard inkomende beleid van ufw in op deny, sta SSH toe, sta 6443 toe vanaf uw eigen adres en sta de pod- en servicenetwerken toe.
- Kopieer de kubeconfig naar uw gebruiker met modus 600 en stel nooit
--write-kubeconfig-mode 644in. - Bevestig dat de kubelet op 10250 anonieme verzoeken weigert en houd de poort afgeschermd van het internet.
- Schakel de gebundelde componenten die u niet gebruikt uit en herstart vervolgens k3s.
- Label uw namespaces voor Pod Security admission met
enforce=baselineenwarn=restricted. - Schakel het automatisch mounten van ServiceAccount-tokens uit.
- Voeg een LimitRange en een ResourceQuota toe en reserveer CPU en geheugen voor k3s.
- Plaats
trivy fs --scanners misconfigin CI en voer maandelijks een CIS-scan uit.
De onderliggende host vereist nog steeds hetzelfde onderhoud als elke andere server, en k3s voegt daar een extra aspect aan toe. Het werd geïnstalleerd via een script in plaats van via apt, dus apt upgrade heeft er geen invloed op. Houd het besturingssysteem volgens een eigen schema bijgewerkt met unattended upgrades op Ubuntu en voer upgrades van k3s bewust uit door het installatiescript opnieuw te draaien met het gewenste kanaal of de gewenste versie. Twee updatepaden op één machine zijn gemakkelijk te vergeten, dus noteer welke component welk pad volgt.
FAQ
Is het veilig om de k3s API-server op poort 6443 bloot te stellen aan het internet?
Het is op zichzelf geen open deur, omdat de API-server een clientcertificaat of een token vereist en al het overige weigert met forbidden: User "system:anonymous". Er blijven twee risico's bestaan. Anonieme bellers kunnen nog steeds /version lezen, wat een scanner precies vertelt naar welke Kubernetes-release gezocht moet worden. Bovendien wordt elk toekomstig beveiligingslek in de API-server op afstand bereikbaar zolang de poort openstaat. Op een cluster met één node heeft niets van buitenaf poort 6443 nodig, behalve uw eigen kubectl. Sta het daarom alleen toe vanaf uw eigen adres met sudo ufw allow from YOUR_IP to any port 6443 proto tcp en laat het standaard 'deny'-beleid de rest afhandelen.
Waarom blokkeert mijn ufw-regel een NodePort-service niet?
Omdat het pakket de chain waarin uw regel zich bevindt nooit bereikt. kube-proxy plaatst DNAT-regels in de PREROUTING-chain van de nat-tabel. Deze wordt als eerste uitgevoerd en herschrijft de bestemming naar een pod-adres. Het pakket wordt vervolgens doorgestuurd in plaats van lokaal afgeleverd, waardoor het de FORWARD-chain doorloopt en de INPUT-chain, waar de regels van ufw staan, overslaat. Bevestig dit met sudo iptables -S PREROUTING -t nat | head. Filter NodePorts bij de netwerkfirewall van uw provider, of vermijd type: NodePort en bereik services in plaats daarvan met kubectl port-forward.
Moet ik k3s draaien met --write-kubeconfig-mode 644?
Nee. De documentatie van k3s legt uit wat dit doet: "Het wijzigen van de modus naar 644 zorgt ervoor dat het bestand gelezen kan worden door andere gebruikers zonder privileges op de host." Dat bestand bevat een clientcertificaat voor system:masters, dus modus 644 maakt van elk lokaal account een clusterbeheerder. Kopieer het in plaats daarvan naar één gebruiker met sudo install -o "$USER" -g "$USER" -m 600 /etc/rancher/k3s/k3s.yaml ~/.kube/config en laat het origineel op 600 root:root staan.
Welke kube-bench benchmark moet ik gebruiken voor k3s?
Gebruik k3s-cis-1.7. De documentatie van kube-bench stelt: "kube-bench bevat benchmarks voor het Rancher K3S-platform. Om dit uit te voeren moet u --benchmark k3s-cis-1.7 opgeven wanneer u het kube-bench-commando uitvoert." Geef dit expliciet mee, omdat automatische detectie uitgaat van een kubeadm-indeling, terwijl k3s zijn bestanden onder /etc/rancher en /var/lib/rancher bewaart. Verwacht foutmeldingen die niet van toepassing zijn op een enkele node, en onderneem eerst actie op bestandsrechten en anonieme toegang.
Zal Pod Security admission de meegeleverde k3s-componenten verbreken?
Dat zal gebeuren als u dit afdwingt op kube-system. De ServiceLB-pods die k3s aanmaakt voor type: LoadBalancer-services claimen poorten op de host, en baseline verbiedt hostpoorten, waardoor die pods worden geweigerd zodra ze opnieuw worden aangemaakt. Vrijgesteld kube-system in het configuratiebestand voor admission, of pas Pod Security alleen toe als labels op de namespaces die u zelf beheert. Begin met enforce=baseline en warn=restricted zodat u kunt lezen wat restricted zou verbreken voordat u het inschakelt.