RBAC e sicurezza
ServiceAccount read-only
Sezione intitolata “ServiceAccount read-only”Un’identità unica per i tool AI: può leggere quasi tutto, non può leggere secret né modificare nulla.
cat > ai-readonly-rbac.yaml <<'EOF2'apiVersion: v1kind: Namespacemetadata: name: ai-tools labels: ai-llm-access: "true"---apiVersion: v1kind: ServiceAccountmetadata: name: ai-readonly namespace: ai-tools---apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRolemetadata: name: ai-readonlyrules: - apiGroups: [""] resources: [pods, pods/log, events, services, endpoints, persistentvolumeclaims, persistentvolumes, nodes, namespaces, replicationcontrollers, resourcequotas, limitranges, serviceaccounts, configmaps] verbs: [get, list, watch] - apiGroups: [apps] resources: [deployments, replicasets, statefulsets, daemonsets] verbs: [get, list, watch] - apiGroups: [batch] resources: [jobs, cronjobs] verbs: [get, list, watch] - apiGroups: [networking.k8s.io] resources: [ingresses, networkpolicies] verbs: [get, list, watch] - apiGroups: [discovery.k8s.io] resources: [endpointslices] verbs: [get, list, watch] - apiGroups: [events.k8s.io] resources: [events] verbs: [get, list, watch] - apiGroups: [storage.k8s.io] resources: [storageclasses, volumeattachments] verbs: [get, list, watch] - apiGroups: [autoscaling] resources: [horizontalpodautoscalers] verbs: [get, list, watch] - apiGroups: [policy] resources: [poddisruptionbudgets] verbs: [get, list, watch] - apiGroups: [metrics.k8s.io] resources: [pods, nodes] verbs: [get, list] - apiGroups: [monitoring.coreos.com] resources: [prometheusrules, servicemonitors, podmonitors] verbs: [get, list, watch] - apiGroups: [apiextensions.k8s.io] resources: [customresourcedefinitions] verbs: [get, list]---apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRoleBindingmetadata: name: ai-readonlyroleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: ai-readonlysubjects: - kind: ServiceAccount name: ai-readonly namespace: ai-toolsEOF2configmaps è incluso perché serve a diagnosticare errori di configurazione; rimuovilo se nel tuo contesto le ConfigMap contengono dati sensibili.
kubectl apply -f ai-readonly-rbac.yamlVerifica:
kubectl auth can-i get secrets -A --as=system:serviceaccount:ai-tools:ai-readonlykubectl auth can-i delete pods -A --as=system:serviceaccount:ai-tools:ai-readonlykubectl auth can-i get pods/log -A --as=system:serviceaccount:ai-tools:ai-readonlykubectl auth can-i create pods/exec -A --as=system:serviceaccount:ai-tools:ai-readonlyAttesi: no, no, yes, no.
Kubeconfig per usare le CLI con il SA
Sezione intitolata “Kubeconfig per usare le CLI con il SA”Per k8sgpt CLI, HolmesGPT CLI e kubectl-ai dal bastion, con gli stessi permessi dell’agente:
TOKEN=$(kubectl -n ai-tools create token ai-readonly --duration=8h)SERVER=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}')kubectl config view --minify --raw -o jsonpath='{.clusters[0].cluster.certificate-authority-data}' | base64 -d > /tmp/ai-ca.crtkubectl config --kubeconfig ~/.kube/ai-readonly set-cluster ai --server="$SERVER" --certificate-authority=/tmp/ai-ca.crt --embed-certs=truekubectl config --kubeconfig ~/.kube/ai-readonly set-credentials ai-readonly --token="$TOKEN"kubectl config --kubeconfig ~/.kube/ai-readonly set-context ai --cluster=ai --user=ai-readonly && kubectl config --kubeconfig ~/.kube/ai-readonly use-context aiKUBECONFIG=~/.kube/ai-readonly holmes ask "what is wrong in namespace <app-namespace>?"NetworkPolicy su ai-llm
Sezione intitolata “NetworkPolicy su ai-llm”Solo i namespace con label ai-llm-access=true raggiungono l’LLM; nessun egress da ai-llm.
cat > ai-llm-netpol.yaml <<'EOF2'apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: default-deny-all namespace: ai-llmspec: podSelector: {} policyTypes: [Ingress, Egress]---apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: allow-llm-from-ai-namespaces namespace: ai-llmspec: podSelector: matchExpressions: - { key: app, operator: In, values: [ollama, vllm] } policyTypes: [Ingress] ingress: - from: - namespaceSelector: matchLabels: ai-llm-access: "true" ports: - { protocol: TCP, port: 11434 } - { protocol: TCP, port: 8000 }---apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: allow-model-fetch-to-registry namespace: ai-llmspec: podSelector: matchExpressions: - { key: app, operator: In, values: [ollama, vllm] } policyTypes: [Egress] egress: - to: - ipBlock: { cidr: <registry-ip>/32 } ports: - { protocol: TCP, port: 443 } - to: - namespaceSelector: {} podSelector: matchLabels: { k8s-app: kube-dns } ports: - { protocol: UDP, port: 53 } - { protocol: TCP, port: 53 }EOF2La terza policy serve solo all’initContainer model-fetcher (registry + DNS). Su OpenShift il selector del DNS è dns.operator.openshift.io/daemonset-dns: default nel namespace openshift-dns.
kubectl apply -f ai-llm-netpol.yamlkubectl label namespace k8sgpt-operator-system ai-llm-access=true --overwritekubectl label namespace holmes ai-llm-access=true --overwriteTest positivo e negativo:
kubectl -n ai-tools run t --rm -it --restart=Never --image=registry.internal/ai/curl:8 -- curl -s -m5 http://ollama.ai-llm.svc:11434/api/versionkubectl -n default run t --rm -it --restart=Never --image=registry.internal/ai/curl:8 -- curl -s -m5 http://ollama.ai-llm.svc:11434/api/version || echo "blocked as expected"Governance
Sezione intitolata “Governance”| Tema | Regola |
|---|---|
| Dati nei prompt | nomi risorse, eventi, log, metriche: restano nel cluster; nessun provider esterno configurato |
| Secret | mai leggibili dagli agenti; niente pods/exec |
| Azioni | gli agenti propongono, gli umani eseguono; nessun permesso di scrittura |
| Audit | audit log dell’API server filtrato sui SA ai-readonly, holmes, k8sgpt |
| Supply chain | immagini e modelli nella pipeline di scan; pin per digest |
| Provenienza modello | repo/commit HF o tag Ollama, quantizzazione, sha256, data import |
| Output | le diagnosi sono suggerimenti: vanno verificate prima di agire |