Skip to content

Berechtigungen und Richtlinien ​

In deinem Namespace bist du weitgehend frei, aber nicht unbegrenzt. Zwei Mechanismen ziehen die Grenze, und sie melden sich unterschiedlich:

  • RBAC entscheidet, welche Ressourcen du überhaupt anfassen darfst. Ein Verstoß endet mit Forbidden.
  • Plattformregeln entscheiden, ob ein konkretes Manifest akzeptiert wird. Ein Verstoß endet damit, dass dein kubectl apply abgelehnt wird.

Was RBAC freigibt ​

"Voll" heißt unten get, list, watch, create, update, patch und delete. Wo eine Zeile etwas Engeres nennt, ist das die gesamte Berechtigung.

API-GruppeRessourcenZugriff
appsdeployments, statefulsets, replicasetsVoll
appsdeployments/scale, statefulsets/scaleget, update, patch
"" (Core, Objekte)services, configmaps, secrets, serviceaccounts, persistentvolumeclaimsVoll
"" (Core, Laufzeit)pods, pods/log, pods/exec, pods/attach, pods/portforward, eventsVoll
"" (Core, Kontingente)resourcequotas, limitrangesNur lesen
"" (Core, Endpoints)endpointsNur lesen
discovery.k8s.ioendpointslicesNur lesen
coordination.k8s.ioleasesVoll
events.k8s.ioeventsNur lesen
batchjobs, cronjobsVoll
autoscalinghorizontalpodautoscalersVoll
autoscaling.k8s.ioverticalpodautoscalersVoll
policypoddisruptionbudgetsVoll
gateway.networking.k8s.iohttproutes, grpcroutesVoll
gateway.nginx.orgclientsettingspoliciesVoll
postgresql.cnpg.ioclusters, backups, scheduledbackups, poolers, databases, publications, subscriptions, imagecatalogsVoll
barmancloud.cnpg.ioobjectstoresVoll
k8s.mariadb.commariadbs, databases, users, grants, connections, backups, restores, sqljobs, maxscalesVoll
dragonflydb.iodragonfliesVoll
keda.shscaledobjects, scaledjobs, triggerauthenticationsVoll
metrics.k8s.iopodsget, list

Alles gilt ausschließlich innerhalb deines Namespace.

Drei Folgen der nur lesbaren Zeilen sind ausdrücklich erwähnenswert:

  • Dein eigenes Kontingent kannst du nicht ändern. Lesen ja, dafür sind kubectl get resourcequota und kubectl describe resourcequota da, aber Erhöhen ist eine Tarifsache, siehe Abrechnung und Kontingente.
  • Die Namespace-Standardwerte kannst du nicht ändern, die für Container ohne eigene Ressourcenangaben gelten.
  • Endpoints kannst du nicht selbst schreiben. Ein Service mit Selector bekommt sie automatisch, ein Service ohne hat keine Backends.

Leases sind für Leader Election und Locks da. Jeder PostgreSQL-Cluster in deinem Namespace hält einen, der so heißt wie der Cluster und auf den sich die Datenbank verlässt, also wähl für deinen eigenen einen anderen Namen. Ein Pod bekommt diesen Zugriff nur, wenn er als Service Account deines Namespace läuft, siehe Netzwerk.

Diese Tabelle beschreibt, was du mit kubectl tun kannst. Wenn du stattdessen deployst, indem du deinen Namespace auf ein Git-Repository zeigen lässt, werden über diesen Weg ein paar Arten nicht angenommen, obwohl sie hier stehen, derzeit Vertical Pod Autoscaler, ClientSettingsPolicies und Leases.

Alles andere ist verboten ​

Was nicht in der Tabelle steht, ist nicht erlaubt. Das betrifft insbesondere Nodes, Namespaces, ClusterRoles und das Verwalten von CRDs. Solche Befehle enden mit Forbidden, siehe Zugang und kubectl.

Die Storage-Klassen kannst du nicht auflisten

kubectl get storageclass ist ebenfalls gesperrt, du kannst die verfügbaren Klassen also nicht aus dem Cluster heraus herausfinden. Es gibt zwei, benannt und beschrieben unter Storage.

Plattformregeln ​

Zusätzlich zu RBAC prüft die Plattform jedes Manifest gegen einen festen Satz Regeln. Die sind hart: Ein Manifest, das dagegen verstößt, wird abgelehnt.

RegelWas du stattdessen tust
Volume-Typen direkt im Pod werden nicht angenommenFordere Speicher über ein PersistentVolumeClaim an
Services vom Typ NodePort, LoadBalancer und ExternalName werden nicht angenommen, spec.externalIPs ebenfalls nichtBleib bei ClusterIP und veröffentliche über eine HTTPRoute
Certificate-Ressourcen kannst du nicht selbst schreibenLass das Zertifikat über die Annotation an deiner HTTPRoute entstehen
Eine HTTPRoute muss mindestens einen Hostnamen angebenOhne Hostnamen würde sie sich als Catch-all an das gemeinsame Gateway hängen
Hostnamen müssen unter deiner Namespace-Subdomain liegen oder im Portal für deinen Namespace freigeschaltet seinSiehe Gateway API
Ein Pod darf sich seinen Node nicht selbst aussuchen und keine Toleration tragen, die auf alles passtÜberlass die Platzierung dem Scheduler. Eine pauschale operator: Exists-Toleration zählt dazu, kopier sie also nicht hinein
Ein Pod darf keine eigene PriorityClass setzenDie passende wird für dich gesetzt
Eine ClientSettingsPolicy darf die Request-Body-Größe nicht über 512 MiB heben und nicht auf null setzenSetz eine explizite Größe innerhalb dieser Grenze
Die HTTP-Ressourcen für Scale-to-Zero werden für dich verwaltetNimm die Annotation itsh.dev/scale-to-zero, siehe Autoscaling
Im Free Tier ist nfs-rwx die einzige zulässige Storage-KlasseSiehe Free Tier

Sandbox-Runtime ​

Deine Workloads laufen in einer Sandbox-Runtime. Sie wird automatisch gesetzt, und abwählen kannst du sie nicht. Für deine eigenen Workloads gibt es dabei nichts zu beachten: Sie wird auch dann gesetzt, wenn du nichts angibst.

An einer Stelle merkst du sie doch. Verwaltete PostgreSQL-Pods sind davon ausgenommen, und weil kubectl exec nur in sandboxed Pods erlaubt ist, kommst du dort nicht per Shell hinein. Siehe Datenbanken.

Inline-Volumes: nimm ein PVC ​

Volume-Typen, die du direkt im Pod definierst, werden abgelehnt. Das betrifft ausdrücklich auch ein nfs-Volume im Pod-Spec:

yaml
# Wird abgelehnt
spec:
  volumes:
    - name: data
      nfs:
        server: nfs.example.com
        path: /export/data

Brauchst du geteilten Speicher, fordere ihn über ein PVC mit der Klasse nfs-rwx an, siehe Storage:

yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: data
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: nfs-rwx
  resources:
    requests:
      storage: 10Gi

Kein NodePort, kein LoadBalancer ​

Nach außen geht es ausschließlich über eine HTTPRoute am gemeinsamen Gateway, siehe Gateway API. Ein Service mit type: LoadBalancer oder type: NodePort wird abgelehnt, ClusterIP ist der richtige Typ.

Zertifikate kommen von der Route ​

Eine Certificate-Ressource selbst anzulegen, wird abgelehnt. TLS entsteht über die Annotation cert-manager.io/cluster-issuer an deiner HTTPRoute, und zwar ohne dein Zutun.

Disruption Budgets und Knotenwartung ​

Knoten werden von Zeit zu Zeit ersetzt, damit sie aktuelle Sicherheitsupdates haben. Deine Pods werden dabei über die Eviction-API vom Knoten verschoben, deine PodDisruptionBudgets gelten also, mit einer Grenze: Ein Pod, der nach 15 Minuten noch auf dem Knoten läuft, weil sein Budget keine Unterbrechung zulässt oder weil er noch herunterfährt, wird gelöscht und hat dafür höchstens eine weitere Minute. Ohne diese Grenze würde ein Budget wie minAvailable: 1 bei einer einzelnen Replica verhindern, dass sein Knoten jemals gepatcht wird.

Damit eine Knotenerneuerung ohne Unterbrechung durchläuft, betreibe mindestens zwei Replicas und stelle das Budget so ein, dass eine davon unterbrochen werden darf.

Wie eine Ablehnung aussieht ​

Verstößt dein Manifest gegen eine Regel, sieht das beim kubectl apply ungefähr so aus:

text
Error from server: error when creating "app.yaml": admission webhook denied the
request: <Begründung, welche Regel verletzt wurde>

Zwei echte Beispiele stehen unter Gateway API, für einen Hostnamen, der dir nicht gehört, und unter Datenbanken, für exec in einen PostgreSQL-Pod.

Der Wortlaut hängt von der Regel ab. Wichtig ist der Unterschied zum Syntaxfehler: denied the request heißt, dass mit deinem YAML alles in Ordnung ist und eine Regel gegriffen hat. Am Manifest gibt es dann nichts zu reparieren, du brauchst einen anderen Ansatz. Welche Regel es war, steht in der Begründung dahinter.

Wie es weitergeht ​