Salta ai contenuti

RBAC e sicurezza

Un’identità unica per i tool AI: può leggere quasi tutto, non può leggere secret né modificare nulla.

Finestra del terminale
cat > ai-readonly-rbac.yaml <<'EOF2'
apiVersion: v1
kind: Namespace
metadata:
name: ai-tools
labels:
ai-llm-access: "true"
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: ai-readonly
namespace: ai-tools
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: ai-readonly
rules:
- 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/v1
kind: ClusterRoleBinding
metadata:
name: ai-readonly
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: ai-readonly
subjects:
- kind: ServiceAccount
name: ai-readonly
namespace: ai-tools
EOF2

configmaps è incluso perché serve a diagnosticare errori di configurazione; rimuovilo se nel tuo contesto le ConfigMap contengono dati sensibili.

Finestra del terminale
kubectl apply -f ai-readonly-rbac.yaml

Verifica:

Finestra del terminale
kubectl auth can-i get secrets -A --as=system:serviceaccount:ai-tools:ai-readonly
Finestra del terminale
kubectl auth can-i delete pods -A --as=system:serviceaccount:ai-tools:ai-readonly
Finestra del terminale
kubectl auth can-i get pods/log -A --as=system:serviceaccount:ai-tools:ai-readonly
Finestra del terminale
kubectl auth can-i create pods/exec -A --as=system:serviceaccount:ai-tools:ai-readonly

Attesi: no, no, yes, no.

Per k8sgpt CLI, HolmesGPT CLI e kubectl-ai dal bastion, con gli stessi permessi dell’agente:

Finestra del terminale
TOKEN=$(kubectl -n ai-tools create token ai-readonly --duration=8h)
Finestra del terminale
SERVER=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}')
Finestra del terminale
kubectl config view --minify --raw -o jsonpath='{.clusters[0].cluster.certificate-authority-data}' | base64 -d > /tmp/ai-ca.crt
Finestra del terminale
kubectl config --kubeconfig ~/.kube/ai-readonly set-cluster ai --server="$SERVER" --certificate-authority=/tmp/ai-ca.crt --embed-certs=true
Finestra del terminale
kubectl config --kubeconfig ~/.kube/ai-readonly set-credentials ai-readonly --token="$TOKEN"
Finestra del terminale
kubectl config --kubeconfig ~/.kube/ai-readonly set-context ai --cluster=ai --user=ai-readonly && kubectl config --kubeconfig ~/.kube/ai-readonly use-context ai
Finestra del terminale
KUBECONFIG=~/.kube/ai-readonly holmes ask "what is wrong in namespace <app-namespace>?"

Solo i namespace con label ai-llm-access=true raggiungono l’LLM; nessun egress da ai-llm.

Finestra del terminale
cat > ai-llm-netpol.yaml <<'EOF2'
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: ai-llm
spec:
podSelector: {}
policyTypes: [Ingress, Egress]
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-llm-from-ai-namespaces
namespace: ai-llm
spec:
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/v1
kind: NetworkPolicy
metadata:
name: allow-model-fetch-to-registry
namespace: ai-llm
spec:
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 }
EOF2

La 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.

Finestra del terminale
kubectl apply -f ai-llm-netpol.yaml
Finestra del terminale
kubectl label namespace k8sgpt-operator-system ai-llm-access=true --overwrite
Finestra del terminale
kubectl label namespace holmes ai-llm-access=true --overwrite

Test positivo e negativo:

Finestra del terminale
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/version
Finestra del terminale
kubectl -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"
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