
Prima o poi, nell'uso di qualsiasi sistema, sorge la questione della sicurezza: garanzia di autenticazione, separazione dei diritti, audit e altre attività. Per Kubernetes sono già stati creati , che permettono di conformarsi agli standard anche in ambienti molto esigenti… Questo materiale è dedicato agli aspetti fondamentali della sicurezza, implementati nei meccanismi integrati di K8s. In primo luogo, sarà utile per coloro che iniziano a esplorare Kubernetes, come punto di partenza per approfondire le questioni legate alla sicurezza.
Autenticazione
In Kubernetes ci sono due tipologie di utenti:
- Service Accounts — account gestiti dall'API Kubernetes;
- Utenti — utenti "normali" gestiti da servizi esterni e indipendenti.
La principale differenza tra questi tipi è che per i Service Accounts esistono oggetti speciali nell'API Kubernetes (che si chiamano proprio così — ServiceAccounts), che sono legati a uno spazio dei nomi e a un insieme di credenziali archiviate nel cluster in oggetti di tipo Secrets. Questi utenti (Service Accounts) sono principalmente destinati alla gestione dei diritti di accesso all'API Kubernetes da parte di processi in esecuzione nel cluster Kubernetes.
Gli Users normali, d'altra parte, non hanno record nell'API Kubernetes: la loro gestione deve essere effettuata tramite meccanismi esterni. Sono destinati a persone o processi che operano al di fuori del cluster.
Ogni richiesta all'API è legata a un Service Account, a un User o è considerata anonima.
Le credenziali dell'utente includono:
- Nome utente — nome utente (dipende dalla registrazione!);
- UID — stringa di identificazione dell'utente leggibile dalla macchina, che è "più coerente e unica del nome utente";
- Groups — elenco dei gruppi a cui appartiene l'utente;
- Extra — campi aggiuntivi che possono essere utilizzati dal meccanismo di autorizzazione.
Kubernetes può utilizzare un gran numero di meccanismi di autenticazione: certificati X509, token Bearer, proxy di autenticazione, HTTP Basic Auth. Grazie a questi meccanismi, è possibile implementare un'ampia varietà di schemi di autorizzazione: da un file statico con password a OpenID OAuth2.
Inoltre, è consentito utilizzare più schemi di autorizzazione contemporaneamente. Per impostazione predefinita, nel cluster sono utilizzati:
- token di account di servizio — per Service Accounts;
- X509 — per Users.
La questione della gestione dei ServiceAccounts va oltre l'ambito di questo articolo, e per chi desidera approfondire l'argomento consiglio di partire dalla . Qui analizzeremo in dettaglio il funzionamento dei certificati X509.
Certificati per utenti (X.509)
Il metodo tradizionale per lavorare con i certificati prevede:
- generazione della chiave:
mkdir -p ~/mynewuser/.certs/ openssl genrsa -out ~/mynewuser.key 2048 - generazione della richiesta di certificato:
openssl req -new -key ~/mynewuser.key -out ~/mynewuser.csr -subj "/CN=mynewuser/O=company" - elaborazione della richiesta di certificato utilizzando le chiavi CA del cluster Kubernetes, ottenendo il certificato utente (per ottenere il certificato è necessario utilizzare un account con accesso alla chiave dell'autorità di certificazione del cluster Kubernetes, che di solito si trova in
/etc/kubernetes/pki/ca.key):openssl x509 -req -in ~/mynewuser.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out ~/mynewuser.crt -days 500 - creazione del file di configurazione:
- descrizione del cluster (specificare l'indirizzo e la posizione del file del certificato CA dell'installazione specifica del cluster):
kubectl config set-cluster kubernetes --certificate-authority=/etc/kubernetes/pki/ca.crt --server=https://192.168.100.200:6443 - oppure — come nonopzione raccomandata — è possibile non specificare il certificato radice (in questo caso kubectl non verificherà la correttezza dell'api-server del cluster):
kubectl config set-cluster kubernetes --insecure-skip-tls-verify=true --server=https://192.168.100.200:6443 - aggiunta dell'utente al file di configurazione:
kubectl config set-credentials mynewuser --client-certificate=.certs/mynewuser.crt --client-key=.certs/mynewuser.key - aggiunta del contesto:
kubectl config set-context mynewuser-context --cluster=kubernetes --namespace=target-namespace --user=mynewuser - designazione del contesto predefinito:
kubectl config use-context mynewuser-context
- descrizione del cluster (specificare l'indirizzo e la posizione del file del certificato CA dell'installazione specifica del cluster):
Dopo le manovre sopra descritte, nel file .kube/config sarà creato un file di configurazione del tipo:
apiVersion: v1
clusters:
- cluster:
certificate-authority: /etc/kubernetes/pki/ca.crt
server: https://192.168.100.200:6443
name: kubernetes
contexts:
- context:
cluster: kubernetes
namespace: target-namespace
user: mynewuser
name: mynewuser-context
current-context: mynewuser-context
kind: Config
preferences: {}
users:
- name: mynewuser
user:
client-certificate: /home/mynewuser/.certs/mynewuser.crt
client-key: /home/mynewuser/.certs/mynewuser.keyPer facilitare il trasferimento della configurazione tra account e server, è utile modificare i valori delle seguenti chiavi:
-
certificate-authority -
client-certificate -
client-key
Per fare ciò, è possibile codificare i file specificati in formato base64 e inserirli nella configurazione, aggiungendo il suffisso al nome delle chiavi -data, ottenendo così certificate-authority-data e così via.
Certificati con kubeadm
Con il rilascio di lavorare con i certificati è diventato significativamente più semplice grazie alla versione alfa del suo supporto in . Ad esempio, ecco come può apparire ora la generazione del file di configurazione con le chiavi utente:
kubeadm alpha kubeconfig user --client-name=mynewuser --apiserver-advertise-address 192.168.100.200 NB: Richiesto indirizzo di pubblicità può essere visualizzato nel file di configurazione dell'api-server, che per impostazione predefinita si trova in /etc/kubernetes/manifests/kube-apiserver.yaml.
Il file di configurazione risultante verrà stampato su stdout. Deve essere salvato nella ~/ .kube / config credenziale utente o in un file specificato nella variabile d'ambiente KUBECONFIG.
Approfondire
Per coloro che desiderano approfondire i temi trattati:
- relativi ai certificati nella documentazione ufficiale di Kubernetes;
- , che affronta la questione dei certificati da una prospettiva pratica.
- sull'autenticazione in Kubernetes.
Autenticazione
L'account autorizzato per impostazione predefinita non ha diritti su azioni nel cluster. Per fornire autorizzazioni in Kubernetes è stato implementato un meccanismo di autorizzazione.
Fino alla versione 1.6, in Kubernetes veniva utilizzato un tipo di autorizzazione chiamato ABAC (controllo degli accessi basato su attributi). Maggiori dettagli al riguardo possono essere trovati in . Attualmente, questo approccio è considerato obsoleto (legacy), tuttavia puoi ancora utilizzarlo insieme ad altri tipi di autorizzazione.
Il modo attuale (e più flessibile) per gestire i diritti di accesso al cluster si chiama RBAC (). È stato dichiarato stabile a partire dalla versione . RBAC attua un modello di diritti in cui tutto è vietato, a meno che non sia esplicitamente consentito.
Per abilitare RBAC, è necessario avviare l'api-server di Kubernetes con il parametro --authorization-mode=RBAC. I parametri vengono specificati nel manifesto di configurazione dell'api-server, che per impostazione predefinita si trova nel percorso /etc/kubernetes/manifests/kube-apiserver.yaml, nella sezione command. Tuttavia, per impostazione predefinita, RBAC è già abilitato, quindi probabilmente non c'è motivo di preoccuparsi: puoi controllarlo dal valore authorization-mode (nella già citata kube-apiserver.yaml). A proposito, tra i suoi valori potrebbero esserci anche altri tipi di autorizzazione (node, webhook, sempre consentire), ma la loro trattazione sarà lasciata fuori dal materiale.
A proposito, abbiamo già pubblicato un racconto abbastanza dettagliato sui principi e le caratteristiche del lavoro con RBAC, quindi per ora mi limiterò a un breve elenco delle basi e degli esempi.
Per la gestione degli accessi in Kubernetes tramite RBAC vengono utilizzate le seguenti entità API:
-
RuoloeClusterRole— ruoli che servono a descrivere i diritti di accesso: -
Ruoloconsente di descrivere i diritti nell'ambito dello spazio dei nomi; -
ClusterRole— nell'ambito del cluster, inclusi gli oggetti specifici del cluster come nodi, url non risorse (cioè non correlati alle risorse Kubernetes — ad esempio,/version,/logs,/api*); -
RoleBindingeClusterRoleBinding— serve per legareRuoloeClusterRolea un utente, a un gruppo di utenti o a un ServiceAccount.
Le entità Role e RoleBinding sono limitate allo spazio dei nomi, cioè devono trovarsi all'interno di un unico spazio dei nomi. Tuttavia, RoleBinding può fare riferimento a ClusterRole, consentendo di creare un insieme di autorizzazioni tipiche e gestire l'accesso utilizzandole.
I ruoli descrivono i diritti tramite insiemi di regole, che contengono:
- gruppi API — vedi per apiGroups e output
kubectl api-resources; - risorse (resources:
pod,namespace,deploymentecc.); - verbi (verbs:
set,aggiornamentoecc.). - nomi delle risorse (
resourceNames) — nel caso in cui sia necessario fornire accesso a una particolare risorsa e non a tutte le risorse di quel tipo.
Una descrizione più dettagliata dell'autorizzazione in Kubernetes può essere trovata nella pagina . Invece di questo (o meglio — in aggiunta a questo) riporterò esempi che illustrano il suo funzionamento.
Esempi di entità RBAC
Semplice Ruolo, consente di ottenere l'elenco e lo stato dei pod e di monitorarli nello spazio dei nomi target-namespace:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: target-namespace
name: pod-reader
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"] Esempio ClusterRole, che consente di ottenere l'elenco e lo stato dei pod e di monitorarli in tutto il cluster:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
# la sezione "namespace" non è presente, poiché ClusterRole utilizza l'intero cluster
name: secret-reader
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "watch", "list"] Esempio RoleBinding, che consente all'utente mynewuser di "leggere" i pod nello spazio dei nomi my-namespace:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
namespace: target-namespace
subjects:
- kind: User
name: mynewuser # nome utente sensibile alle maiuscole!
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role # qui deve essere “Role” o “ClusterRole”
name: pod-reader # nome del Role, che si trova nello stesso spazio dei nomi,
# o nome del ClusterRole, il cui utilizzo
# vogliamo consentire all'utente
apiGroup: rbac.authorization.k8s.ioAudit degli eventi
Schema dell'architettura Kubernetes può essere rappresentato come segue:

Il componente chiave di Kubernetes, responsabile della gestione delle richieste, è api-server. Tutte le operazioni sul cluster passano attraverso di esso. Maggiori dettagli su questi meccanismi interni possono essere trovati nell'articolo «».
L'audit del sistema è una funzionalità interessante in Kubernetes, che è disabilitata per impostazione predefinita. Permette di registrare tutte le richieste all'API di Kubernetes. Come si può facilmente intuire, attraverso questa API si eseguono tutte le operazioni relative al controllo e alla modifica dello stato del cluster. Una buona descrizione delle sue capacità può essere (come al solito) trovata in K8s. Ora cercherò di esporre l'argomento in un linguaggio più semplice.
Quindi, Per attivare l'audit, dobbiamo passare al container nell'api-server tre parametri obbligatori, di cui parlerò dettagliatamente qui di seguito:
-
--audit-policy-file=/etc/kubernetes/policies/audit-policy.yaml -
--audit-log-path=/var/log/kube-audit/audit.log -
--audit-log-format=json
Oltre a questi tre parametri necessari, esistono molte altre impostazioni relative all'audit: dalla rotazione dei log alle descrizioni dei webhook. Ecco un esempio di parametri per la rotazione dei log:
-
--audit-log-maxbackup=10 -
--audit-log-maxsize=100 -
--audit-log-maxage=7
Ma non ci soffermeremo ulteriormente su di essi: tutti i dettagli possono essere trovati nella .
Come già menzionato, tutti i parametri sono impostati nel manifesto di configurazione dell'api-server (di default /etc/kubernetes/manifests/kube-apiserver.yaml), nella sezione command. Torniamo ai 3 parametri obbligatori e analizziamoli:
-
audit-policy-file— il percorso del file YAML contenente la politica di audit. Torneremo sul suo contenuto, ma intanto segnalo che il file deve essere leggibile dal processo dell'api-server. Pertanto, è necessario montarlo all'interno del container, per farlo si può aggiungere il seguente codice alle sezioni appropriate della configurazione:volumeMounts: - mountPath: /etc/kubernetes/policies name: policies readOnly: true volumes: - hostPath: path: /etc/kubernetes/policies type: DirectoryOrCreate name: policies -
audit-log-path— il percorso del file di log. Anche questo percorso deve essere accessibile dal processo dell'api-server, quindi descriviamo in modo analogo il suo montaggio:volumeMounts: - mountPath: /var/log/kube-audit name: logs readOnly: false volumes: - hostPath: path: /var/log/kube-audit type: DirectoryOrCreate name: logs -
audit-log-format— il formato del log di audit. Di default questo èjson, ma è disponibile anche un formato testuale obsoleto (legacy).
Politica di audit
Ora parliamo del file menzionato con la descrizione della politica di logging. Il primo concetto di audit policy è level, il livello di logging. I livelli possono essere i seguenti:
-
Nessuno— non registrare; -
Metadata— registrare i metadati della richiesta: utente, ora della richiesta, risorsa target (pod, namespace, ecc.), tipo di azione (verb) e così via; -
Request— registrare i metadati e il corpo della richiesta; -
RequestResponse— registrare i metadati, il corpo della richiesta e il corpo della risposta.
Gli ultimi due livelli (Request e RequestResponse) non registrano le richieste che non accedono alle risorse (richieste a cosiddetti URLs non risorse).
Inoltre, tutte le richieste passano attraverso diverse fasi:
-
RequestReceived— fase in cui la richiesta è stata ricevuta dal gestore e non è ancora stata trasferita lungo la catena di gestori; -
ResponseStarted— le intestazioni della risposta sono state inviate, ma prima dell'invio del corpo della risposta. Viene generato per richieste di lunga durata (ad esempio,watch); -
ResponseComplete— il corpo della risposta è stato inviato, non verranno inviate ulteriori informazioni; -
Panic— gli eventi vengono generati quando si verifica una situazione anomala.
Per saltare alcune fasi, è possibile utilizzare omitStages.
Nel file di policy possiamo descrivere diverse sezioni con vari livelli di registrazione. Sarà applicata la prima regola corrispondente trovata nella descrizione della policy.
Il demone kubelet monitora le modifiche al manifesto con la configurazione dell'api-server e, quando ne rileva, riavvia il contenitore con l'api-server. Ma c'è un dettaglio importante: le modifiche al file di policy verranno ignorate da esso. Dopo aver apportato modifiche al file di policy, sarà necessario riavviare manualmente l'api-server. Poiché l'api-server è eseguito come , il comando kubectl delete non porterà al suo riavvio. Sarà necessario eseguire manualmente docker stop sui kube-master dove è stata modificata la policy di audit:
docker stop $(docker ps | grep k8s_kube-apiserver | awk '{print $1}')Quando si attiva l'audit, è importante ricordare che il carico sul kube-apiserver aumenta. In particolare, aumenta il consumo di memoria per conservare il contesto delle richieste. La registrazione nel log inizia solo dopo l'invio dell'intestazione della risposta. Inoltre, il carico dipende dalla configurazione della policy di audit.
Esempi di politiche
Analizziamo la struttura dei file di policy tramite esempi.
Ecco un semplice file policy, per registrare tutto a livello di Metadata:
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: Metadata Nella policy è possibile specificare un elenco di utenti (Utenti e ServiceAccounts) e gruppi di utenti. Ad esempio, così faremo per ignorare gli utenti di sistema, ma registrare tutto il resto a livello di Request:
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: None
userGroups:
- "system:serviceaccounts"
- "system:nodes"
users:
- "system:anonymous"
- "system:apiserver"
- "system:kube-controller-manager"
- "system:kube-scheduler"
- level: RequestC'è anche la possibilità di descrivere gli obiettivi:
- spazi dei nomi (
namespace); - verbi (verbs:
get,aggiornamento,deletee altri); - risorse (resources, cioè:
pod,configmapsecc.) e gruppi di risorse (apiGroups).
Attenzione! Le risorse e i gruppi di risorse (gruppi API, cioè apiGroups), così come le loro versioni, installate nel cluster, possono essere ottenute tramite i comandi:
kubectl api-resources
kubectl api-versionsLa seguente audit policy è fornita come dimostrazione delle migliori pratiche nella :
apiVersion: audit.k8s.io/v1beta1
kind: Policy
# Non registrare la fase RequestReceived
omitStages:
- "RequestReceived"
rules:
# Non registrare eventi considerati di poco significato e non pericolosi:
- level: None
users: ["system:kube-proxy"]
verbs: ["watch"]
resources:
- group: "" # questo è il gruppo api con nome vuoto, a cui appartengono
# le risorse di base di Kubernetes, chiamate "core"
resources: ["endpoints", "services"]
- level: None
users: ["system:unsecured"]
namespaces: ["kube-system"]
verbs: ["get"]
resources:
- group: "" # core
resources: ["configmaps"]
- level: None
users: ["kubelet"]
verbs: ["get"]
resources:
- group: "" # core
resources: ["nodes"]
- level: None
userGroups: ["system:nodes"]
verbs: ["get"]
resources:
- group: "" # core
resources: ["nodes"]
- level: None
users:
- system:kube-controller-manager
- system:kube-scheduler
- system:serviceaccount:kube-system:endpoint-controller
verbs: ["get", "update"]
namespaces: ["kube-system"]
resources:
- group: "" # core
resources: ["endpoints"]
- level: None
users: ["system:apiserver"]
verbs: ["get"]
resources:
- group: "" # core
resources: ["namespaces"]
# Non registrare le richieste a URL di sola lettura:
- level: None
nonResourceURLs:
- /healthz*
- /version
- /swagger*
# Non registrare i messaggi relativi a risorse di tipo "eventi":
- level: None
resources:
- group: "" # core
resources: ["events"]
# Le risorse di tipo Secret, ConfigMap e TokenReview possono contenere
# dati riservati,
# quindi registriamo solo i metadati delle richieste correlate
- level: Metadata
resources:
- group: "" # core
resources: ["secrets", "configmaps"]
- group: authentication.k8s.io
resources: ["tokenreviews"]
# Le azioni di tipo get, list e watch possono essere onerose; non le registriamo
- level: Request
verbs: ["get", "list", "watch"]
resources:
- group: "" # core
- group: "admissionregistration.k8s.io"
- group: "apps"
- group: "authentication.k8s.io"
- group: "authorization.k8s.io"
- group: "autoscaling"
- group: "batch"
- group: "certificates.k8s.io"
- group: "extensions"
- group: "networking.k8s.io"
- group: "policy"
- group: "rbac.authorization.k8s.io"
- group: "settings.k8s.io"
- group: "storage.k8s.io"
# Livello di registrazione predefinito per le risorse API standard
- level: RequestResponse
resources:
- group: "" # core
- group: "admissionregistration.k8s.io"
- group: "apps"
- group: "authentication.k8s.io"
- group: "authorization.k8s.io"
- group: "autoscaling"
- group: "batch"
- group: "certificates.k8s.io"
- group: "extensions"
- group: "networking.k8s.io"
- group: "policy"
- group: "rbac.authorization.k8s.io"
- group: "settings.k8s.io"
- group: "storage.k8s.io"
# Livello di registrazione predefinito per tutte le altre richieste
- level: MetadataUn altro buon esempio di politica di audit — .
Per rispondere rapidamente agli eventi di audit, c'è la possibilità di descrivere un webhook. Questa questione è trattata in , lo lascerò fuori dai confini di questo articolo.
Conclusioni
L'articolo offre una panoramica dei meccanismi di sicurezza di base nei cluster Kubernetes, che consentono di creare account utente personalizzati, separare i loro diritti e registrare le loro azioni. Spero che sia utile a chi si è trovato di fronte a tali questioni, sia in teoria che in pratica. Raccomando anche di prendere visione dell'elenco di altri materiali sulla sicurezza in Kubernetes, riportato nel «P.S.», poiché tra di essi potreste trovare dettagli pertinenti ai vostri problemi attuali.
P.S.
Leggi anche nel nostro blog:
- «»;
- «»;
- «»;
- «»;
- «».
Fonte: habr.com
