Kubernetes Basics

Concetti di base di Kubernetes

Impara l'hacking di AWS da zero a eroe con htARTE (HackTricks AWS Red Team Expert)!

Altri modi per supportare HackTricks:

L'autore originale di questa pagina è Jorge (leggi il suo post originale qui)

Architettura e concetti di base

Cosa fa Kubernetes?

  • Consente l'esecuzione di uno o più container in un motore di container.

  • La pianificazione consente una missione efficiente dei container.

  • Mantiene i container attivi.

  • Consente la comunicazione tra i container.

  • Consente tecniche di distribuzione.

  • Gestisce volumi di informazioni.

Architettura

  • Nodo: sistema operativo con pod o pod.

  • Pod: Wrapper attorno a un container o più container. Un pod dovrebbe contenere solo un'applicazione (quindi di solito, un pod esegue solo 1 container). Il pod è il modo in cui Kubernetes astrae la tecnologia dei container in esecuzione.

  • Servizio: Ogni pod ha 1 indirizzo IP interno dall'intervallo interno del nodo. Tuttavia, può essere anche esposto tramite un servizio. Il servizio ha anche un indirizzo IP e il suo obiettivo è mantenere la comunicazione tra i pod in modo che se uno muore il nuovo sostituto (con un diverso IP interno) sarà accessibile esposto nello stesso IP del servizio. Può essere configurato come interno o esterno. Il servizio agisce anche come bilanciamento del carico quando 2 pod sono collegati allo stesso servizio. Quando viene creato un servizio, è possibile trovare gli endpoint di ogni servizio eseguendo kubectl get endpoints

  • Kubelet: Agente primario del nodo. Il componente che stabilisce la comunicazione tra il nodo e kubectl e può eseguire solo pod (tramite il server API). Il kubelet non gestisce i container che non sono stati creati da Kubernetes.

  • Kube-proxy: è il servizio responsabile delle comunicazioni (servizi) tra l'apiserver e il nodo. La base è un IPtables per i nodi. Gli utenti più esperti potrebbero installare altri kube-proxy da altri fornitori.

  • Container sidecar: I container sidecar sono i container che devono essere eseguiti insieme al container principale nel pod. Questo modello sidecar estende e migliora la funzionalità dei container attuali senza modificarli. Oggi sappiamo che utilizziamo la tecnologia dei container per incapsulare tutte le dipendenze per l'esecuzione dell'applicazione ovunque. Un container fa solo una cosa e lo fa molto bene.

  • Processo master:

  • Api Server: È il modo in cui gli utenti e i pod comunicano con il processo master. Dovrebbero essere consentite solo richieste autenticate.

  • Scheduler: La pianificazione si riferisce a garantire che i pod siano abbinati ai nodi in modo che Kubelet possa eseguirli. Ha sufficiente intelligenza per decidere quale nodo ha più risorse disponibili per assegnare il nuovo pod ad esso. Si noti che lo scheduler non avvia nuovi pod, comunica solo con il processo Kubelet in esecuzione all'interno del nodo, che avvierà il nuovo pod.

  • Kube Controller Manager: Controlla le risorse come i set di repliche o le distribuzioni per verificare se, ad esempio, il numero corretto di pod o nodi è in esecuzione. Nel caso in cui manchi un pod, comunicherà con lo scheduler per avviarne uno nuovo. Controlla la replica, i token e i servizi di account per l'API.

  • etcd: Archiviazione dati, persistente, coerente e distribuita. È il database di Kubernetes e lo storage chiave-valore in cui conserva lo stato completo dei cluster (ogni modifica viene registrata qui). Componenti come lo Scheduler o il Controller Manager dipendono da questa data per sapere quali modifiche sono state apportate (risorse disponibili dei nodi, numero di pod in esecuzione...)

  • Cloud Controller Manager: È il controller specifico per il controllo dei flussi e delle applicazioni, ad esempio: se si hanno cluster in AWS o OpenStack.

Si noti che poiché potrebbero esserci diversi nodi (che eseguono diversi pod), potrebbero anche esserci diversi processi master con accesso bilanciato al server API e la loro etcd sincronizzata.

Volumi:

Quando un pod crea dati che non devono essere persi quando il pod scompare, dovrebbero essere archiviati in un volume fisico. Kubernetes consente di allegare un volume a un pod per persistere i dati. Il volume può essere nella macchina locale o in un archivio remoto. Se si eseguono pod su diversi nodi fisici, è necessario utilizzare un archivio remoto in modo che tutti i pod possano accedervi.

Altre configurazioni:

  • ConfigMap: È possibile configurare URL per accedere ai servizi. Il pod otterrà i dati da qui per sapere come comunicare con il resto dei servizi (pod). Si noti che questo non è il posto consigliato per salvare le credenziali!

  • Secret: Questo è il luogo in cui memorizzare dati segreti come password, chiavi API... codificati in B64. Il pod sarà in grado di accedere a questi dati per utilizzare le credenziali richieste.

  • Deployments: Qui vengono indicati i componenti da eseguire tramite Kubernetes. Di solito, un utente non lavorerà direttamente con i pod, i pod sono astratti in ReplicaSets (numero di pod replicati), che vengono eseguiti tramite i deployments. Si noti che i deployments sono per applicazioni senza stato. La configurazione minima per un deployment è il nome e l'immagine da eseguire.

  • StatefulSet: Questo componente è specificamente destinato a applicazioni come database che devono accedere allo stesso archivio.

  • Ingress: Questa è la configurazione che viene utilizzata per esporre l'applicazione pubblicamente con un URL. Si noti che ciò può essere fatto anche utilizzando servizi esterni, ma questa è la modalità corretta per esporre l'applicazione.

  • Se si implementa un Ingress, sarà necessario creare Ingress Controllers. L'Ingress Controller è un pod che sarà il punto finale che riceverà le richieste, le verificherà e le bilancerà sui servizi. l'Ingress Controller inoltrerà la richiesta in base alle regole di ingress configurate. Si noti che le regole di ingress possono puntare a percorsi diversi o addirittura a sottodomini di diversi servizi interni di Kubernetes.

  • Una pratica di sicurezza migliore sarebbe utilizzare un bilanciatore di carico cloud o un server proxy come punto di ingresso per non avere alcuna parte del cluster Kubernetes esposta.

  • Quando viene ricevuta una richiesta che non corrisponde a nessuna regola di ingress, l'Ingress Controller la indirizzerà al "Default backend". È possibile eseguire il comando describe sull'Ingress Controller per ottenere l'indirizzo di questo parametro.

  • minikube addons enable ingress

Infrastruttura PKI - Autorità di Certificazione CA:

  • CA è la radice fidata per tutti i certificati all'interno del cluster.

  • Consente ai componenti di convalidarsi reciprocamente.

  • Tutti i certificati del cluster sono firmati dalla CA.

  • ETCd ha il suo certificato.

  • Tipi:

  • Certificato apiserver.

  • Certificato kubelet.

  • Certificato scheduler.

Azioni di base

Minikube

Minikube può essere utilizzato per eseguire alcuni test rapidi su Kubernetes senza la necessità di distribuire un intero ambiente Kubernetes. Eseguirà i processi master e node in una sola macchina. Minikube utilizzerà virtualbox per eseguire il nodo. Vedi qui come installarlo.

$ minikube start
😄  minikube v1.19.0 on Ubuntu 20.04
✨  Automatically selected the virtualbox driver. Other choices: none, ssh
💿  Downloading VM boot image ...
> minikube-v1.19.0.iso.sha256: 65 B / 65 B [-------------] 100.00% ? p/s 0s
> minikube-v1.19.0.iso: 244.49 MiB / 244.49 MiB  100.00% 1.78 MiB p/s 2m17.
👍  Starting control plane node minikube in cluster minikube
💾  Downloading Kubernetes v1.20.2 preload ...
> preloaded-images-k8s-v10-v1...: 491.71 MiB / 491.71 MiB  100.00% 2.59 MiB
🔥  Creating virtualbox VM (CPUs=2, Memory=3900MB, Disk=20000MB) ...
🐳  Preparing Kubernetes v1.20.2 on Docker 20.10.4 ...
▪ Generating certificates and keys ...
▪ Booting up control plane ...
▪ Configuring RBAC rules ...
🔎  Verifying Kubernetes components...
▪ Using image gcr.io/k8s-minikube/storage-provisioner:v5
🌟  Enabled addons: storage-provisioner, default-storageclass
🏄  Done! kubectl is now configured to use "minikube" cluster and "default" namespace by defaul

$ minikube status
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured

---- ONCE YOU HAVE A K8 SERVICE RUNNING WITH AN EXTERNAL SERVICE -----
$ minikube service mongo-express-service
(This will open your browser to access the service exposed port)

$ minikube delete
🔥  Deleting "minikube" in virtualbox ...
💀  Removed all traces of the "minikube" cluster

Concetti di base di Kubectl

Kubectl è lo strumento da riga di comando per i cluster di Kubernetes. Comunica con il server API del processo master per eseguire azioni in Kubernetes o per richiedere dati.

kubectl version #Get client and server version
kubectl get pod
kubectl get services
kubectl get deployment
kubectl get replicaset
kubectl get secret
kubectl get all
kubectl get ingress
kubectl get endpoints

#kubectl create deployment <deployment-name> --image=<docker image>
kubectl create deployment nginx-deployment --image=nginx
#Access the configuration of the deployment and modify it
#kubectl edit deployment <deployment-name>
kubectl edit deployment nginx-deployment
#Get the logs of the pod for debbugging (the output of the docker container running)
#kubectl logs <replicaset-id/pod-id>
kubectl logs nginx-deployment-84cd76b964
#kubectl describe pod <pod-id>
kubectl describe pod mongo-depl-5fd6b7d4b4-kkt9q
#kubectl exec -it <pod-id> -- bash
kubectl exec -it mongo-depl-5fd6b7d4b4-kkt9q -- bash
#kubectl describe service <service-name>
kubectl describe service mongodb-service
#kubectl delete deployment <deployment-name>
kubectl delete deployment mongo-depl
#Deploy from config file
kubectl apply -f deployment.yml

Dashboard di Minikube

Il dashboard ti permette di vedere più facilmente cosa sta eseguendo Minikube, puoi trovare l'URL per accedervi in:

minikube dashboard --url


🔌  Enabling dashboard ...
▪ Using image kubernetesui/dashboard:v2.3.1
▪ Using image kubernetesui/metrics-scraper:v1.0.7
🤔  Verifying dashboard health ...
🚀  Launching proxy ...
🤔  Verifying proxy health ...
http://127.0.0.1:50034/api/v1/namespaces/kubernetes-dashboard/services/http:kubernetes-dashboard:/proxy/

Esempi di file di configurazione YAML

Ogni file di configurazione ha 3 parti: metadata, specification (cosa deve essere avviato), status (stato desiderato). All'interno della specifica del file di configurazione del deployment è possibile trovare il template definito con una nuova struttura di configurazione che definisce l'immagine da eseguire:

Esempio di Deployment + Service dichiarati nello stesso file di configurazione (da qui)

Poiché un servizio di solito è correlato a un deployment, è possibile dichiarare entrambi nello stesso file di configurazione (il servizio dichiarato in questa configurazione è accessibile solo internamente):

apiVersion: apps/v1
kind: Deployment
metadata:
name: mongodb-deployment
labels:
app: mongodb
spec:
replicas: 1
selector:
matchLabels:
app: mongodb
template:
metadata:
labels:
app: mongodb
spec:
containers:
- name: mongodb
image: mongo
ports:
- containerPort: 27017
env:
- name: MONGO_INITDB_ROOT_USERNAME
valueFrom:
secretKeyRef:
name: mongodb-secret
key: mongo-root-username
- name: MONGO_INITDB_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mongodb-secret
key: mongo-root-password
---
apiVersion: v1
kind: Service
metadata:
name: mongodb-service
spec:
selector:
app: mongodb
ports:
- protocol: TCP
port: 27017
targetPort: 27017

Esempio di configurazione di un servizio esterno

Questo servizio sarà accessibile esternamente (controlla gli attributi nodePort e type: LoadBalancer):

---
apiVersion: v1
kind: Service
metadata:
name: mongo-express-service
spec:
selector:
app: mongo-express
type: LoadBalancer
ports:
- protocol: TCP
port: 8081
targetPort: 8081
nodePort: 30000

Questo è utile per il testing, ma per la produzione dovresti avere solo servizi interni e un Ingress per esporre l'applicazione.

Esempio di file di configurazione Ingress

Questo esporrà l'applicazione su http://dashboard.com.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: dashboard-ingress
namespace: kubernetes-dashboard
spec:
rules:
- host: dashboard.com
http:
paths:
- backend:
serviceName: kubernetes-dashboard
servicePort: 80

Esempio di file di configurazione dei segreti

Nota come le password siano codificate in B64 (che non è sicuro!)

apiVersion: v1
kind: Secret
metadata:
name: mongodb-secret
type: Opaque
data:
mongo-root-username: dXNlcm5hbWU=
mongo-root-password: cGFzc3dvcmQ=

Esempio di ConfigMap

Un ConfigMap è la configurazione fornita ai pod in modo che sappiano come individuare e accedere ad altri servizi. In questo caso, ogni pod saprà che il nome mongodb-service è l'indirizzo di un pod con cui possono comunicare (questo pod eseguirà un'istanza di mongodb):

apiVersion: v1
kind: ConfigMap
metadata:
name: mongodb-configmap
data:
database_url: mongodb-service

Quindi, all'interno di una configurazione di deployment, questo indirizzo può essere specificato nel seguente modo in modo che venga caricato all'interno dell'env del pod:

[...]
spec:
[...]
template:
[...]
spec:
containers:
- name: mongo-express
image: mongo-express
ports:
- containerPort: 8081
env:
- name: ME_CONFIG_MONGODB_SERVER
valueFrom:
configMapKeyRef:
name: mongodb-configmap
key: database_url
[...]

Esempio di configurazione del volume

Puoi trovare diversi esempi di file di configurazione yaml per lo storage su https://gitlab.com/nanuchi/youtube-tutorial-series/-/tree/master/kubernetes-volumes. Nota che i volumi non sono all'interno dei namespace

Namespaces

Kubernetes supporta cluster virtuali multipli supportati dallo stesso cluster fisico. Questi cluster virtuali sono chiamati namespaces. Sono pensati per essere utilizzati in ambienti con molti utenti distribuiti su più team o progetti. Per cluster con pochi o decine di utenti, non dovresti aver bisogno di creare o pensare ai namespaces. Dovresti iniziare ad utilizzare i namespaces solo per avere un migliore controllo e organizzazione di ogni parte dell'applicazione distribuita in Kubernetes.

I namespaces forniscono uno scope per i nomi. I nomi delle risorse devono essere univoci all'interno di un namespace, ma non tra i namespaces. I namespaces non possono essere nidificati l'uno dentro l'altro e ogni risorsa di Kubernetes può essere solo in un namespace.

Ci sono 4 namespaces di default se stai usando minikube:

kubectl get namespace
NAME              STATUS   AGE
default           Active   1d
kube-node-lease   Active   1d
kube-public       Active   1d
kube-system       Active   1d
  • kube-system: Non è destinato all'uso degli utenti e non dovresti toccarlo. È per i processi master e kubectl.

  • kube-public: Dati accessibili pubblicamente. Contiene un configmap che contiene informazioni sul cluster.

  • kube-node-lease: Determina la disponibilità di un nodo.

  • default: Lo spazio dei nomi che l'utente utilizzerà per creare risorse.

#Create namespace
kubectl create namespace my-namespace

Nota che la maggior parte delle risorse di Kubernetes (ad esempio, pod, servizi, controller di replica e altri) sono in alcuni namespace. Tuttavia, altre risorse come le risorse di namespace e le risorse di basso livello, come i nodi e i volumi persistenti, non sono in un namespace. Per vedere quali risorse di Kubernetes sono e non sono in un namespace:

kubectl api-resources --namespaced=true #In a namespace
kubectl api-resources --namespaced=false #Not in a namespace

Puoi salvare il namespace per tutti i comandi successivi di kubectl in quel contesto.

kubectl config set-context --current --namespace=<insert-namespace-name-here>

Helm

Helm è il gestore di pacchetti per Kubernetes. Consente di impacchettare file YAML e distribuirli in repository pubbliche e private. Questi pacchetti sono chiamati Helm Charts.

helm search <keyword>

Helm è anche un motore di template che consente di generare file di configurazione con variabili:

Secret di Kubernetes

Un Secret è un oggetto che contiene dati sensibili come una password, un token o una chiave. Tali informazioni potrebbero altrimenti essere inserite in una specifica Pod o in un'immagine. Gli utenti possono creare Secret e il sistema crea anche Secret. Il nome di un oggetto Secret deve essere un valido nome di sottodominio DNS. Leggi qui la documentazione ufficiale.

I Secret potrebbero essere cose come:

  • API, chiavi SSH.

  • Token OAuth.

  • Credenziali, password (testo normale o b64 + crittografia).

  • Informazioni o commenti.

  • Codice di connessione al database, stringhe... .

Ci sono diversi tipi di Secret in Kubernetes

Tipo incorporatoUtilizzo

Opaque

dati definiti dall'utente arbitrari (predefinito)

kubernetes.io/service-account-token

token dell'account di servizio

kubernetes.io/dockercfg

file ~/.dockercfg serializzato

kubernetes.io/dockerconfigjson

file ~/.docker/config.json serializzato

kubernetes.io/basic-auth

credenziali per l'autenticazione di base

kubernetes.io/ssh-auth

credenziali per l'autenticazione SSH

kubernetes.io/tls

dati per un client o server TLS

bootstrap.kubernetes.io/token

dati del token di bootstrap

Il tipo Opaque è quello predefinito, la coppia chiave-valore tipica definita dagli utenti.

Come funzionano i Secret:

Il seguente file di configurazione definisce un secret chiamato mysecret con 2 coppie chiave-valore username: YWRtaW4= e password: MWYyZDFlMmU2N2Rm. Definisce anche una pod chiamata secretpod che avrà username e password definiti in mysecret esposti nelle variabili d'ambiente SECRET_USERNAME e SECRET_PASSWORD. Monta anche il secret username all'interno di mysecret nel percorso /etc/foo/my-group/my-username con permessi 0640.

secretpod.yaml
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
username: YWRtaW4=
password: MWYyZDFlMmU2N2Rm
---
apiVersion: v1
kind: Pod
metadata:
name: secretpod
spec:
containers:
- name: secretpod
image: nginx
env:
- name: SECRET_USERNAME
valueFrom:
secretKeyRef:
name: mysecret
key: username
- name: SECRET_PASSWORD
valueFrom:
secretKeyRef:
name: mysecret
key: password
volumeMounts:
- name: foo
mountPath: "/etc/foo"
restartPolicy: Never
volumes:
- name: foo
secret:
secretName: mysecret
items:
- key: username
path: my-group/my-username
mode: 0640
kubectl apply -f <secretpod.yaml>
kubectl get pods #Wait until the pod secretpod is running
kubectl exec -it  secretpod -- bash
env | grep SECRET && cat /etc/foo/my-group/my-username && echo

Secreti in etcd

etcd è un archivio chiave-valore coerente e altamente disponibile utilizzato come archivio di supporto di Kubernetes per tutti i dati del cluster. Accediamo ai segreti archiviati in etcd:

cat /etc/kubernetes/manifests/kube-apiserver.yaml | grep etcd

Vedrai che i certificati, le chiavi e gli URL sono situati nel file system. Una volta ottenuti, sarai in grado di connetterti a etcd.

#ETCDCTL_API=3 etcdctl --cert <path to client.crt> --key <path to client.ket> --cacert <path to CA.cert> endpoint=[<ip:port>] health

ETCDCTL_API=3 etcdctl --cert /etc/kubernetes/pki/apiserver-etcd-client.crt --key /etc/kubernetes/pki/apiserver-etcd-client.key --cacert /etc/kubernetes/pki/etcd/etcd/ca.cert endpoint=[127.0.0.1:1234] health

Una volta che riesci a stabilire la comunicazione, sarai in grado di ottenere i segreti:

#ETCDCTL_API=3 etcdctl --cert <path to client.crt> --key <path to client.ket> --cacert <path to CA.cert> endpoint=[<ip:port>] get <path/to/secret>

ETCDCTL_API=3 etcdctl --cert /etc/kubernetes/pki/apiserver-etcd-client.crt --key /etc/kubernetes/pki/apiserver-etcd-client.key --cacert /etc/kubernetes/pki/etcd/etcd/ca.cert endpoint=[127.0.0.1:1234] get /registry/secrets/default/secret_02

Aggiunta di crittografia all'ETCD

Di default, tutti i segreti vengono archiviati in chiaro all'interno di etcd a meno che non si applichi uno strato di crittografia. L'esempio seguente si basa su https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/

encryption.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: cjjPMcWpTPKhAdieVtd+KhG4NN+N6e3NmBPMXJvbfrY= #Any random key
- identity: {}

Dopo di ciò, è necessario impostare il flag --encryption-provider-config sul kube-apiserver per puntare alla posizione del file di configurazione creato. Puoi modificare /etc/kubernetes/manifest/kube-apiserver.yaml e aggiungere le seguenti righe:

containers:
- command:
- kube-apiserver
- --encriyption-provider-config=/etc/kubernetes/etcd/<configFile.yaml>

Scorri verso il basso in volumeMounts:

- mountPath: /etc/kubernetes/etcd
name: etcd
readOnly: true

Scorri verso il basso in volumeMounts fino a hostPath:

- hostPath:
path: /etc/kubernetes/etcd
type: DirectoryOrCreate
name: etcd

Verifica che i dati siano criptati

I dati vengono criptati quando vengono scritti su etcd. Dopo aver riavviato il tuo kube-apiserver, ogni nuovo segreto creato o aggiornato dovrebbe essere criptato quando viene memorizzato. Per verificare ciò, puoi utilizzare il programma a riga di comando etcdctl per recuperare il contenuto del tuo segreto.

  1. Crea un nuovo segreto chiamato secret1 nel namespace default:

kubectl create secret generic secret1 -n default --from-literal=mykey=mydata
  1. Utilizzando il comando etcdctl, leggi quel segreto da etcd:

ETCDCTL_API=3 etcdctl get /registry/secrets/default/secret1 [...] | hexdump -C

dove [...] devono essere gli argomenti aggiuntivi per connettersi al server etcd. 3. Verifica che il segreto memorizzato abbia il prefisso k8s:enc:aescbc:v1:, che indica che il provider aescbc ha criptato i dati risultanti. 4. Verifica che il segreto venga correttamente decrittato quando viene recuperato tramite l'API:

kubectl describe secret secret1 -n default

dovrebbe corrispondere a mykey: bXlkYXRh, mydata è codificato, controlla decodifica di un segreto per decodificare completamente il segreto.

Poiché i segreti vengono criptati durante la scrittura, eseguire un aggiornamento su un segreto cripterà quel contenuto:

kubectl get secrets --all-namespaces -o json | kubectl replace -f -

Suggerimenti finali:

Riferimenti

Impara l'hacking di AWS da zero a eroe con htARTE (HackTricks AWS Red Team Expert)!

Altri modi per supportare HackTricks:

Last updated