Kubernetes Basics

Kubernetes Basiese beginsels

Leer AWS-hacking van nul tot held met htARTE (HackTricks AWS Red Team Expert)!

Ander maniere om HackTricks te ondersteun:

Die oorspronklike skrywer van hierdie bladsy is Jorge (lees sy oorspronklike pos hier)

Argitektuur & Basiese beginsels

Wat doen Kubernetes?

  • Maak dit moontlik om 'n houer/s in 'n houermotor te laat loop.

  • Skeduleer maak dit moontlik om houers doeltreffend te laat loop.

  • Hou houers aan die gang.

  • Maak kommunikasie tussen houers moontlik.

  • Maak implementeringstegnieke moontlik.

  • Hanteer groot hoeveelhede inligting.

Argitektuur

  • Node: bedryfstelsel met pod of pods.

  • Pod: Verpakking om 'n houer of verskeie houers met. 'n Pod behoort slegs een toepassing te bevat (so gewoonlik loop 'n pod net 1 houer). Die pod is die manier waarop Kubernetes die houer-tegnologie wat loop, abstraheer.

  • Diens: Elke pod het 1 interne IP-adres uit die interne reeks van die node. Dit kan egter ook blootgestel word deur 'n diens. Die diens het ook 'n IP-adres en sy doel is om die kommunikasie tussen pods te handhaaf, sodat as een sterf, die nuwe vervanging (met 'n ander interne IP) toeganklik sal wees wat blootgestel word in dieselfde IP van die diens. Dit kan as intern of ekstern gekonfigureer word. Die diens tree ook op as 'n laaibalanseerder wanneer 2 pods aan dieselfde diens gekoppel is. Wanneer 'n diens geskep word, kan jy die eindpunte van elke diens vind deur kubectl get endpoints uit te voer.

  • Kubelet: Primêre nodus-agent. Die komponent wat kommunikasie tussen die nodus en kubectl vestig, en slegs pods kan laat loop (deur API-bediener). Die kubelet bestuur nie houers wat nie deur Kubernetes geskep is nie.

  • Kube-proxy: is die diens wat verantwoordelik is vir die kommunikasie (dienste) tussen die API-bediener en die nodus. Die basis is 'n IP-tabelle vir nodusse. Die meeste ervare gebruikers kan ander kube-proxies van ander verskaffers installeer.

  • Sidecar-houer: Sidecar-houers is die houers wat saam met die hoofhouer in die pod moet loop. Hierdie sidecar-patroon brei die funksionaliteit van huidige houers uit sonder om hulle te verander. Vandag weet ons dat ons houertegnologie gebruik om al die afhanklikhede vir die toepassing in te sluit sodat dit oral kan loop. 'n Houer doen slegs een ding en doen dit baie goed.

  • Meesterproses:

  • API-bediener: Dit is die manier waarop gebruikers en pods kommunikeer met die meesterproses. Slegs geauthentiseerde versoek moet toegelaat word.

  • Skeduleerder: Skedulering verwys daarna om seker te maak dat Pods aan Nodusse gekoppel word sodat Kubelet dit kan laat loop. Dit het genoeg intelligensie om te besluit watter nodus meer beskikbare hulpbronne het en die nuwe pod daaraan toe te ken. Let daarop dat die skeduleerder nie nuwe pods begin nie, dit kommunikeer net met die Kubelet-proses wat binne die nodus loop, wat die nuwe pod sal begin.

  • Kube-beheerder: Dit kontroleer hulpbronne soos replikasette of implementerings om te kyk of, byvoorbeeld, die korrekte aantal pods of nodusse loop. In die geval van 'n ontbrekende pod, sal dit kommunikeer met die skeduleerder om 'n nuwe een te begin. Dit beheer replikasie, tokens en rekeningdienste vir die API.

  • etcd: Data-opberging, volhoudend, konsekwent en verspreid. Dit is Kubernetes se databasis en die sleutel-waarde-opberging waar dit die volledige toestand van die groepe hou (elke verandering word hier geregistreer). Komponente soos die Skeduleerder of die Beheerder vertrou op hierdie data om te weet watter veranderinge plaasgevind het (beskikbare hulpbronne van die nodusse, aantal loopende pods...)

  • Cloud-beheerder vir beheerders: Dit is die spesifieke beheerder vir vloeibeheer en aansoeke, bv. as jy groepe het in AWS of OpenStack.

Let daarop dat daar, aangesien daar verskeie nodusse kan wees (wat verskeie pods laat loop), ook verskeie meesterprosesse kan wees waarvan die toegang tot die API-bediener gebalanseer word en hul etcd-gesinkroniseer word.

Volume:

Wanneer 'n pod data skep wat nie verlore mag gaan wanneer die pod verdwyn nie, moet dit in 'n fisiese volume gestoor word. Kubernetes maak dit moontlik om 'n volume aan 'n pod te heg om die data volhoubaar te maak. Die volume kan op die plaaslike masjien of in 'n afgeleë stoorplek wees. As jy pods op verskillende fisiese nodusse laat loop, moet jy 'n afgeleë stoorplek gebruik sodat al die pods daartoe toegang kan hê.

Ander konfigurasies:

  • ConfigMap: Jy kan URL's konfigureer om toegang tot dienste te verkry. Die pod sal data van hierdie plek verkry om te weet hoe om met die res van die dienste (pods) te kommunikeer. Let daarop dat dit nie die aanbevole plek is om geloofsbriewe te stoor nie!

  • Geheim: Dit is die plek om geheime data soos wagwoorde, API-sleutels... wat in B64 gekodeer is, te stoor. Die pod sal toegang tot hierdie data hê om die vereiste geloofsbriewe te gebruik.

  • Implementerings: Hier word die komponente aangedui wat deur Kubernetes uitgevoer moet word. 'n Gebruiker sal gewoonlik nie direk met pods werk nie, pods word geabstraheer in ReplicaSets (aantal gelyke pods gerepliseer), wat uitgevoer word via implementerings. Let daarop dat implementerings vir stateless toepassings is. Die minimumkonfigurasie vir 'n implementering is die naam en die beeld om uit te voer.

  • StatefulSet: Hierdie komponent is spesifiek bedoel vir toepassings soos databasisse wat toegang tot dieselfde stoorplek benodig.

  • Ingress: Hierdie is die konfigurasie wat gebruik word om die toepassing openlik met 'n URL bloot te stel. Let daarop dat dit ook gedoen kan word deur gebruik te maak van eksterne dienste, maar dit is die korrekte manier om die toepassing bloot te stel.

  • As jy 'n Ingress implementeer, sal jy Ingress-controllers moet skep. Die Ingress Controller is 'n pod wat die eindpunt sal wees wat die versoek sal ontvang en sal ondersoek en sal dit na die dienste laaibalanseer. die ingress controller sal die

PKI-infrastruktuur - Sertifikaatowerheid CA:

  • CA is die vertroude wortel vir alle sertifikate binne die groep.

  • Maak dit vir komponente moontlik om mekaar te valideer.

  • Alle groepsertifikate word deur die CA onderteken.

  • ETCd het sy eie sertifikaat.

  • tipes:

  • apiserver-sertifikaat.

  • kubelet-sertifikaat.

  • skeduleerder-sertifikaat.

Basiese Aksies

Minikube

Minikube kan gebruik word om vinnige toetse op kubernetes uit te voer sonder om 'n hele kubernetes-omgewing te implementeer. Dit sal die meester- en nodusprosesse op een masjien uitvoer. Minikube sal virtualbox gebruik om die nodus uit te voer. Sien hier hoe om dit te installeer.

$ 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

Kubectl Basiese Beginsels

Kubectl is die opdraglynhulpmiddel vir kubernetes-klusters. Dit kommunikeer met die Api-bediener van die meesterproses om aksies in kubernetes uit te voer of om vir data te vra.

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-paneel

Die paneel stel jou in staat om makliker te sien wat minikube aan die hardloop is. Jy kan die URL vind om dit te bereik 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/

YAML-konfigurasie-lêervoorbeelde

Elke konfigurasie-lêer het 3 dele: metadata, spesifikasie (wat moet geloods word), status (gewenste toestand). Binne die spesifikasie van die implementeringskonfigurasie-lêer kan jy die sjabloon vind wat gedefinieer is met 'n nuwe konfigurasie-struktuur wat die beeld om te hardloop definieer:

Voorbeeld van implementering + Diens wat in dieselfde konfigurasie-lêer verklaar is (vanaf hier)

Aangesien 'n diens gewoonlik verband hou met een implementering, is dit moontlik om beide in dieselfde konfigurasie-lêer te verklaar (die diens wat in hierdie konfigurasie verklaar is, is slegs intern toeganklik):

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

Voorbeeld van eksterne dienskonfigurasie

Hierdie diens sal ekstern toeganklik wees (kontroleer die nodePort en type: LoadBalancer eienskappe):

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

Dit is nuttig vir toetsing, maar vir produksie moet jy slegs interne dienste hê en 'n Ingress om die aansoek bloot te stel.

Voorbeeld van Ingress konfigurasie lêer

Dit sal die aansoek blootstel in 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

Voorbeeld van geheime konfigurasie lêer

Merk op hoe die wagwoorde in B64 gekodeer is (wat nie veilig is nie!)

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

Voorbeeld van ConfigMap

'n ConfigMap is die konfigurasie wat aan die pods gegee word sodat hulle weet hoe om ander dienste te vind en toegang te verkry. In hierdie geval sal elke pod weet dat die naam mongodb-service die adres van 'n pod is waarmee hulle kan kommunikeer (hierdie pod sal 'n mongodb uitvoer):

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

Dan, binne 'n implementeringskonfigurasie, kan hierdie adres op die volgende manier gespesifiseer word sodat dit in die omgewing van die houer gelaai word:

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

Voorbeeld van volume-configuratie

Jy kan verskillende voorbeelde van stoorconfigurasiyaml-lêers vind by https://gitlab.com/nanuchi/youtube-tutorial-series/-/tree/master/kubernetes-volumes. Let daarop dat volumes nie binne namespaces is nie

Namespaces

Kubernetes ondersteun veelvuldige virtuele klusters wat ondersteun word deur dieselfde fisiese kluster. Hierdie virtuele klusters word namespaces genoem. Dit is bedoel vir gebruik in omgewings met baie gebruikers wat versprei is oor verskeie spanne of projekte. Vir klusters met 'n paar tot tientalle gebruikers, hoef jy nie namespaces te skep of daaroor te dink nie. Jy moet slegs namespaces begin gebruik om beter beheer en organisasie van elke deel van die toepassing wat in Kubernetes geïmplementeer is, te hê.

Namespaces bied 'n omvang vir name. Name van hulpbronne moet uniek wees binne 'n namespace, maar nie oor namespaces heen nie. Namespaces kan nie binne mekaar geneste word nie en elke Kubernetes hulpbron kan slegs in een namespace wees.

Daar is 4 namespaces standaard as jy minikube gebruik:

kubectl get namespace
NAME              STATUS   AGE
default           Active   1d
kube-node-lease   Active   1d
kube-public       Active   1d
kube-system       Active   1d
  • kube-system: Dit is nie bedoel vir gebruik deur gebruikers nie en jy moet dit nie aanraak nie. Dit is vir die meester en kubectl prosesse.

  • kube-public: Openlik toeganklike data. Bevat 'n configmap wat klusterinligting bevat.

  • kube-node-lease: Bepaal die beskikbaarheid van 'n node.

  • default: Die naamruimte wat die gebruiker sal gebruik om hulpbronne te skep.

#Create namespace
kubectl create namespace my-namespace

Let daarop dat die meeste Kubernetes-bronne (bv. peule, dienste, replikasie-controllers en ander) in sekere namespaces is. Ander bronne, soos namespaces-bronne en lae-vlak bronne, soos nodes en persistenVolumes, is egter nie in 'n namespace nie. Om te sien watter Kubernetes-bronne wel en nie in 'n namespace is:

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

Jy kan die namespace stoor vir al die volgende kubectl-opdragte in daardie konteks.

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

Helm

Helm is die pakketbestuurder vir Kubernetes. Dit maak dit moontlik om YAML-lêers te verpak en hulle in openbare en private bewaarplekke te versprei. Hierdie pakkette word Helm-grafieke genoem.

helm search <keyword>

Helm is ook 'n sjabloon-enjin wat dit moontlik maak om konfigurasie lêers met veranderlikes te genereer:

Kubernetes-geheime

'n Geheim is 'n voorwerp wat sensitiewe data soos 'n wagwoord, 'n token of 'n sleutel bevat. Sulke inligting kan andersins in 'n Pod-spesifikasie of in 'n beeld geplaas word. Gebruikers kan Geheime skep en die stelsel skep ook Geheime. Die naam van 'n Geheim-voorwerp moet 'n geldige DNS-subdomeinnaam wees. Lees hier die amptelike dokumentasie.

Geheime kan dinge wees soos:

  • API, SSH-sleutels.

  • OAuth-tokens.

  • Geloofsbriewe, Wagwoorde (plain text of b64 + enkripsie).

  • Inligting of kommentaar.

  • Databasisverbindingskode, strings...

Daar is verskillende tipes geheime in Kubernetes

Ingeboude TipeGebruik

Ondoorgrond

arbitrêre gebruikersgedefinieerde data (Verstek)

kubernetes.io/service-account-token

diensrekening-token

kubernetes.io/dockercfg

geserialiseerde ~/.dockercfg-lêer

kubernetes.io/dockerconfigjson

geserialiseerde ~/.docker/config.json-lêer

kubernetes.io/basic-auth

geloofsbriewe vir basiese outentifikasie

kubernetes.io/ssh-auth

geloofsbriewe vir SSH-outentifikasie

kubernetes.io/tls

data vir 'n TLS-kliënt of -bediener

bootstrap.kubernetes.io/token

bootstrap-token-data

Die Ondoorgrondse tipe is die verstek een, die tipiese sleutel-waardepaar wat deur gebruikers gedefinieer word.

Hoe geheime werk:

Die volgende konfigurasie-lêer definieer 'n geheim genaamd mysecret met 2 sleutel-waardepare username: YWRtaW4= en password: MWYyZDFlMmU2N2Rm. Dit definieer ook 'n pod genaamd secretpod wat die username en password wat in mysecret gedefinieer is, blootgestel sal hê in die omgewingsveranderlikes SECRET_USERNAME en SECRET_PASSWOR. Dit sal ook die username-geheim binne mysecret monteer in die pad /etc/foo/my-group/my-username met 0640-permissies.

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

Geheime in etcd

etcd is 'n konsekwente en hoogs beskikbare sleutel-waarde stoor wat gebruik word as die Kubernetes agterste stoor vir alle kluster data. Laat ons toegang verkry tot die geheime wat in etcd gestoor is:

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

Jy sal sien sertifikate, sleutels en url's is geleë in die FS. Sodra jy dit kry, sal jy in staat wees om met etcd te verbind.

#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

Sodra jy kommunikasie tot stand bring, sal jy in staat wees om die geheime te bekom:

#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

Die byvoeging van versleuteling tot die ETCD

Standaard word alle geheime inligting as plain text binne etcd gestoor, tensy jy 'n versleutelingslaag toepas. Die volgende voorbeeld is gebaseer op 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: {}

Daarna moet jy die --encryption-provider-config vlag stel op die kube-apiserver om te verwys na die plek waar die geskepde konfigurasie-lêer is. Jy kan /etc/kubernetes/manifest/kube-apiserver.yaml wysig en die volgende lyne byvoeg:

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

Bla

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

Bla

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

Verifieer dat data versleutel is

Data word versleutel wanneer dit na etcd geskryf word. Nadat jy jou kube-apiserver herlaai het, behoort enige nuut geskep of opgedateerde geheim versleutel te word wanneer dit gestoor word. Om te verifieer, kan jy die etcdctl opdraglynprogram gebruik om die inhoud van jou geheim te herwin.

  1. Skep 'n nuwe geheim genaamd secret1 in die default namespace:

kubectl create secret generic secret1 -n default --from-literal=mykey=mydata
  1. Gebruik die etcdctl opdraglyn om daardie geheim uit etcd te lees:

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

waar [...] die bykomende argumente moet wees om met die etcd-bediener te verbind. 3. Verifieer dat die gestoorde geheim voorafgegaan word deur k8s:enc:aescbc:v1:, wat aandui dat die aescbc-verskaffer die resulterende data versleutel het. 4. Verifieer dat die geheim korrek ontsleutel word wanneer dit via die API herwin word:

kubectl describe secret secret1 -n default

moet ooreenstem met mykey: bXlkYXRh, mydata is gekodeer, sien ontkodering van 'n geheim om die geheim volledig te ontkodeer.

Aangesien geheime versleutel word tydens skryf, sal 'n opdatering op 'n geheim daardie inhoud versleutel:

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

Finale wenke:

Verwysings

Leer AWS-hacking van nul tot held met htARTE (HackTricks AWS Red Team Expert)!

Ander maniere om HackTricks te ondersteun:

Last updated