Kubernetes Basics

Osnove Kubernetesa

Naučite hakovanje AWS-a od nule do heroja sa htARTE (HackTricks AWS Red Team Expert)!

Drugi načini podrške HackTricks-u:

Originalni autor ove stranice je Jorge (pročitajte njegov originalni post ovde)

Arhitektura i osnove

Šta radi Kubernetes?

  • Omogućava pokretanje kontejnera u kontejnerskom okruženju.

  • Planiranje omogućava efikasno izvršavanje kontejnera.

  • Održava kontejnere aktivnim.

  • Omogućava komunikaciju između kontejnera.

  • Omogućava tehnike implementacije.

  • Upravlja obimom informacija.

Arhitektura

  • Čvor: operativni sistem sa podom ili podovima.

  • Pod: Omotač oko jednog ili više kontejnera. Jedan pod treba da sadrži samo jednu aplikaciju (tako da obično jedan pod pokreće samo 1 kontejner). Pod je način na koji Kubernetes apstrahuje tehnologiju kontejnera koja se izvršava.

  • Servis: Svaki pod ima 1 internu IP adresu iz interne opsega čvora. Međutim, može biti izložen i putem servisa. Servis takođe ima IP adresu i njegov cilj je održavanje komunikacije između podova, tako da ako jedan umre, novi zamena (sa drugom internom IP adresom) će biti dostupan izložen na isto IP adrese servisa. Može biti konfigurisan kao interni ili eksterni. Servis takođe deluje kao balanser opterećenja kada su 2 poda povezana na isti servis. Kada se kreira servis, možete pronaći krajnje tačke svakog servisa pokretanjem kubectl get endpoints

  • Kubelet: Primarni čvorski agent. Komponenta koja uspostavlja komunikaciju između čvora i kubectl-a i može pokretati samo podove (putem API servera). Kubelet ne upravlja kontejnerima koji nisu kreirani od strane Kubernetes-a.

  • Kube-proxy: je servis koji je zadužen za komunikaciju (servisi) između api servera i čvora. Osnova su IPtables za čvorove. Iskusniji korisnici mogu instalirati druge kube-proksije od drugih dobavljača.

  • Sidecar kontejner: Sidecar kontejneri su kontejneri koji treba da se pokreću zajedno sa glavnim kontejnerom u podu. Ovaj sidecar obrazac proširuje i poboljšava funkcionalnost trenutnih kontejnera bez njihove promene. Danas znamo da koristimo tehnologiju kontejnera da bismo zapakovali sve zavisnosti kako bi aplikacija mogla da se pokrene bilo gde. Kontejner radi samo jednu stvar i to radi veoma dobro.

  • Glavni proces:

  • API server: Način na koji korisnici i podovi komuniciraju sa glavnim procesom. Dozvoljeni su samo autentifikovani zahtevi.

  • Planer: Planiranje se odnosi na to da se osigura da se podovi uparuju sa čvorovima kako bi Kubelet mogao da ih pokrene. Ima dovoljno inteligencije da odluči koji čvor ima više dostupnih resursa i dodeli novi pod njemu. Napomena: planer ne pokreće nove podove, samo komunicira sa Kubelet procesom koji se izvršava unutar čvora, koji će pokrenuti novi pod.

  • Kube Controller menadžer: Proverava resurse kao što su skupovi replika ili implementacije kako bi proverio da li, na primer, radi ispravan broj podova ili čvorova. U slučaju da pod nedostaje, komuniciraće sa planerom da pokrene novi. Kontroliše replikaciju, tokene i usluge naloga za API.

  • etcd: Skladište podataka, trajno, dosledno i distribuirano. To je baza podataka Kubernetes-a i skladište ključ-vrednost gde čuva potpuno stanje klastera (svaka promena se beleži ovde). Komponente poput Planera ili Menadžera kontrolora zavise od ovih podataka kako bi znale koje promene su se dogodile (dostupni resursi čvorova, broj pokrenutih podova...).

  • Menadžer kontrolera u oblaku: Specifičan kontroler za kontrolu protoka i aplikacija, npr. ako imate klaster u AWS-u ili OpenStack-u.

Imajte na umu da može biti više čvorova (koji pokreću više podova), može biti i više glavnih procesa čiji pristup Api serveru je ravnotežen i njihov etcd je sinhronizovan.

Volumeni:

Kada pod kreira podatke koji ne smeju biti izgubljeni kada pod nestane, treba ih čuvati na fizičkom volumenu. Kubernetes omogućava povezivanje volumena sa podom kako bi se podaci sačuvali. Volumen može biti na lokalnom računaru ili na udaljenom skladištu. Ako pokrećete podove na različitim fizičkim čvorovima, trebali biste koristiti udaljeno skladište kako bi svi podovi mogli da mu pristupe.

Druga konfiguracija:

  • ConfigMap: Možete konfigurisati URL-ove za pristup uslugama. Pod će dobiti podatke odavde kako bi znao kako da komunicira sa ostalim uslugama (podovima). Imajte na umu da ovo nije preporučeno mesto za čuvanje akreditiva!

  • Tajna: Ovo je mesto za čuvanje tajnih podataka poput lozinki, API ključeva... kodiranih u B64 formatu. Pod će moći da pristupi ovim podacima kako bi koristio potrebne akreditive.

  • Implementacije: Ovde se navode komponente koje će pokretati Kubernetes. Korisnik obično neće direktno raditi sa podovima, podovi su apstrahovani u ReplicaSet-ove (broj istih replika podova), koji se pokreću putem implementacija. Napomena: implementacije su za bezstanovne aplikacije. Minimalna konfiguracija za implementaciju je ime i slika koju treba pokrenuti.

  • StatefulSet: Ova komponenta je namenjena posebno za aplikacije poput baza podataka koje moraju da pristupe istom skladištu.

  • Ingress: Ovo je konfiguracija koja se koristi za javno izlaganje aplikacije putem URL-a. Imajte na umu da se to može uraditi i pomoću spoljnih usluga, ali ovo je ispravan način izlaganja aplikacije.

  • Ako implementirate Ingress, moraćete da kreirate Ingress kontrolere. In

PKI infrastruktura - Sertifikacioni autoritet CA:

  • CA je pouzdani koren za sve sertifikate unutar klastera.

  • Omogućava komponentama da se međusobno validiraju.

  • Svi klaster sertifikati su potpisani od strane CA.

  • ETCd ima svoj sopstveni sertifikat.

  • Tipovi:

  • Sertifikat apiservera.

  • Sertifikat kubeleta.

  • Sertifikat scheduler-a.

Osnovne radnje

Minikube

Minikube se može koristiti za izvođenje brzih testova na Kubernetesu bez potrebe za implementacijom celokupnog Kubernetes okruženja. Pokrenuće master i node procese na jednom računaru. Minikube će koristiti virtualbox za pokretanje node-a. Pogledajte ovde kako ga instalirati.

$ 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

Osnove Kubectl-a

Kubectl je alat za komandnu liniju za kubernetes klaster. Komunicira sa Api serverom glavnog procesa kako bi izvršio radnje u kubernetesu ili zatražio podatke.

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

Minikube kontrolna tabla

Kontrolna tabla vam omogućava da lakše vidite šta minikube radi, URL za pristup možete pronaći u:

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/

Primeri YAML konfiguracionih fajlova

Svaki konfiguracioni fajl ima 3 dela: metadata, specifikacija (šta treba da se pokrene), status (željeno stanje). Unutar specifikacije konfiguracionog fajla za implementaciju, možete pronaći šablon definisan novom konfiguracionom strukturom koja definiše sliku koja će se pokrenuti:

Primer Deployment + Service deklarisani u istom konfiguracionom fajlu (sa ovde)

Pošto je servis obično povezan sa jednom implementacijom, moguće je deklarisati oba u istom konfiguracionom fajlu (servis deklarisan u ovom konfigu je dostupan samo interno):

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

Primer konfiguracije spoljnog servisa

Ovaj servis će biti dostupan spolja (proverite atribute nodePort i 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

Ovo je korisno za testiranje, ali za produkciju trebate imati samo interne usluge i Ingress za izlaganje aplikacije.

Primer konfiguracionog fajla za Ingress

Ovo će izložiti aplikaciju na 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

Primer konfiguracionog fajla sa tajnama

Primetite kako su lozinke kodirane u B64 (što nije bezbedno!)

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

Primer ConfigMap-a

ConfigMap je konfiguracija koja se daje podovima kako bi znali kako da pronađu i pristupe drugim servisima. U ovom slučaju, svaki pod će znati da je naziv mongodb-service adresa poda sa kojim mogu komunicirati (ovaj pod će izvršavati mongodb):

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

Zatim, unutar konfiguracije implementacije ova adresa može biti specificirana na sledeći način kako bi se učitala unutar okruženja poda:

[...]
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
[...]

Primer konfiguracije zapisa

Različiti primeri konfiguracije skladišta u YAML formatu mogu se pronaći na https://gitlab.com/nanuchi/youtube-tutorial-series/-/tree/master/kubernetes-volumes. Napomena: zapisi nisu unutar imenskih prostora

Imenski prostori

Kubernetes podržava više virtuelnih klastera podržanih istim fizičkim klasterom. Ovi virtuelni klasteri nazivaju se imenski prostori. Namijenjeni su za upotrebu u okruženjima sa mnogo korisnika raspoređenih u više timova ili projekata. Za klaster sa nekoliko do desetina korisnika, ne biste trebali morati stvarati ili razmišljati o imenskim prostorima. Imenske prostore trebate koristiti samo kako biste imali bolju kontrolu i organizaciju svakog dijela aplikacije koja je implementirana u Kubernetes-u.

Imenski prostori pružaju opseg za imena. Imena resursa moraju biti jedinstvena unutar imenskog prostora, ali ne i između imenskih prostora. Imenski prostori ne mogu biti ugniježđeni jedan u drugi i svaki Kubernetes resurs može biti samo u jednom imenskom prostoru.

Ako koristite minikube, podrazumijevano postoje 4 imenska prostora.

kubectl get namespace
NAME              STATUS   AGE
default           Active   1d
kube-node-lease   Active   1d
kube-public       Active   1d
kube-system       Active   1d
  • kube-system: Nije namenjen korisnicima i ne treba ga dirati. Koristi se za procese mastera i kubectl.

  • kube-public: Javno dostupni podaci. Sadrži configmap koji sadrži informacije o klasteru.

  • kube-node-lease: Određuje dostupnost čvora.

  • default: Imenik koji korisnik koristi za kreiranje resursa.

#Create namespace
kubectl create namespace my-namespace

Imajte na umu da se većina Kubernetes resursa (npr. podovi, servisi, kontroleri replikacija i drugi) nalazi u nekim namespace-ima. Međutim, drugi resursi poput namespace resursa i resursa niskog nivoa, kao što su čvorovi i persistenVolume-ovi, nisu u namespace-u. Da biste videli koji Kubernetes resursi jesu i nisu u namespace-u:

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

Možete sačuvati namespace za sve naredne kubectl komande u tom kontekstu.

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

Helm

Helm je upravljač paketima za Kubernetes. Omogućava pakovanje YAML datoteka i njihovu distribuciju u javnim i privatnim repozitorijumima. Ovi paketi se nazivaju Helm Charts.

helm search <keyword>

Helm je takođe šablonski motor koji omogućava generisanje konfiguracionih fajlova sa promenljivama:

Kubernetes tajne

Tajna je objekat koji sadrži osetljive podatke kao što su lozinka, token ili ključ. Takve informacije bi inače bile smeštene u specifikaciji Pod-a ili u slici. Korisnici mogu kreirati Tajne, a sistem takođe kreira Tajne. Ime objekta Tajne mora biti validno DNS poddomensko ime. Pročitajte ovde zvaničnu dokumentaciju.

Tajne mogu biti stvari kao što su:

  • API, SSH ključevi.

  • OAuth tokeni.

  • Kredencijali, lozinke (čisti tekst ili b64 + enkripcija).

  • Informacije ili komentari.

  • Kod za povezivanje sa bazom podataka, stringovi... .

Postoje različite vrste tajni u Kubernetes-u

Ugrađena vrstaUpotreba

Opač

proizvoljni podaci definisani od strane korisnika (podrazumevano)

kubernetes.io/service-account-token

token za servisni nalog

kubernetes.io/dockercfg

serijalizovani ~/.dockercfg fajl

kubernetes.io/dockerconfigjson

serijalizovani ~/.docker/config.json fajl

kubernetes.io/basic-auth

kredencijali za osnovnu autentifikaciju

kubernetes.io/ssh-auth

kredencijali za SSH autentifikaciju

kubernetes.io/tls

podaci za TLS klijenta ili servera

bootstrap.kubernetes.io/token

podaci o početnom token-u

Opač vrsta je podrazumevana, tipičan par ključ-vrednost definisan od strane korisnika.

Kako tajne funkcionišu:

Sledeći konfiguracioni fajl definiše tajnu nazvanu mysecret sa 2 parova ključ-vrednost username: YWRtaW4= i password: MWYyZDFlMmU2N2Rm. Takođe definiše pod nazvan secretpod koji će imati username i password definisane u mysecret izložene u okruženjskim promenljivama SECRET_USERNAME __ i __ SECRET_PASSWOR. Takođe će montirati tajnu username unutar mysecret na putanju /etc/foo/my-group/my-username sa dozvolama 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

Tajne u etcd

etcd je dosledno i visoko dostupno skladište ključ-vrednost koje se koristi kao podrška za Kubernetes za sve podatke klastera. Hajde da pristupimo tajnama koje su smeštene u etcd-u:

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

Videćete da se sertifikati, ključevi i URL-ovi nalaze u FS-u. Kada to dobijete, bićete u mogućnosti da se povežete sa etcd-om.

#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

Jednom kada uspostavite komunikaciju, bićete u mogućnosti da dobijete tajne:

#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

Dodavanje enkripcije na ETCD

Podrazumevano, svi tajni podaci se čuvaju u običnom tekstu unutar etcd, osim ako ne primenite sloj enkripcije. Sledeći primer je zasnovan na 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: {}

Nakon toga, trebate postaviti --encryption-provider-config zastavicu na kube-apiserver da bi pokazala na lokaciju kreiranog konfiguracionog fajla. Možete izmeniti /etc/kubernetes/manifest/kube-apiserver.yaml i dodati sledeće linije:

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

Pomerite se nadole u volumeMounts:

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

Pomerite se nadole u volumeMounts do hostPath:

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

Provera da li su podaci šifrovani

Podaci se šifruju prilikom upisa u etcd. Nakon restartovanja kube-apiservera, svaki novokreirani ili ažurirani tajni podatak trebao bi biti šifrovan prilikom skladištenja. Da biste to proverili, možete koristiti etcdctl komandnu liniju da biste dobili sadržaj vašeg tajnog podatka.

  1. Kreirajte novi tajni podatak pod nazivom secret1 u podrazumevanom (default) namespace-u:

kubectl create secret generic secret1 -n default --from-literal=mykey=mydata
  1. Koristeći etcdctl komandnu liniju, pročitajte tajni podatak iz etcd:

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

gde [...] moraju biti dodatni argumenti za povezivanje sa etcd serverom. 3. Proverite da li je sačuvani tajni podatak prefiksan sa k8s:enc:aescbc:v1:, što ukazuje da je aescbc provajder šifrovao rezultirajuće podatke. 4. Proverite da li je tajni podatak ispravno dešifrovan prilikom dobijanja putem API-ja:

kubectl describe secret secret1 -n default

trebalo bi da se poklapa sa mykey: bXlkYXRh, mydata je kodiran, proverite dekodiranje tajnog podatka da biste potpuno dekodirali tajni podatak.

Pošto su tajni podaci šifrovani prilikom ažuriranja, izvršavanje ažuriranja na tajnom podatku će šifrovati taj sadržaj:

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

Konačni saveti:

Reference

Naučite hakovanje AWS-a od nule do heroja sa htARTE (HackTricks AWS Red Team Expert)!

Drugi načini da podržite HackTricks:

Last updated