Kubernetes Basics

Основи Kubernetes

Вивчайте хакінг AWS від нуля до героя з htARTE (HackTricks AWS Red Team Expert)!

Інші способи підтримки HackTricks:

Оригінальний автор цієї сторінки Хорхе (читайте його оригінальний пост тут)

Архітектура та Основи

Що робить Kubernetes?

  • Дозволяє запуск контейнера/ів у контейнерному двигуні.

  • Розклад дозволяє контейнерам ефективно виконувати завдання.

  • Підтримує життєздатність контейнерів.

  • Дозволяє комунікацію між контейнерами.

  • Дозволяє техніки розгортання.

  • Обробляє обсяги інформації.

Архітектура

  • Вузол (Node): операційна система з підсистемою або підсистемами.

  • Підсистема (Pod): Обгортка навколо контейнера або кількох контейнерів. Підсистема повинна містити лише одну програму (таким чином, зазвичай, підсистема запускає лише 1 контейнер). Підсистема - це спосіб, яким Kubernetes абстрагує технологію контейнерів, що працює.

  • Служба (Service): Кожна підсистема має 1 внутрішню IP-адресу з внутрішнього діапазону вузла. Однак його також можна використовувати через службу. Служба також має IP-адресу і її мета полягає в підтримці зв'язку між підсистемами, тому якщо одна вмирає, новий замінник (з іншою внутрішньою IP) буде доступний через ту саму IP-адресу служби. Його можна налаштувати як внутрішній або зовнішній. Служба також діє як балансувальник навантаження, коли 2 підсистеми підключені до однієї служби. Коли створюється служба, ви можете знайти кінцеві точки кожної служби, запустивши kubectl get endpoints

  • Kubelet: Основний агент вузла. Компонент, який встановлює зв'язок між вузлом та kubectl, і може запускати лише підсистеми (через сервер API). Kubelet не керує контейнерами, які не були створені Kubernetes.

  • Kube-proxy: це служба, відповідальна за комунікації (служби) між apiserver та вузлом. Основа - це IPtables для вузлів. Досвідчені користувачі можуть встановлювати інші kube-proxy від інших вендорів.

  • Бічний контейнер (Sidecar container): Бічні контейнери - це контейнери, які повинні працювати разом з основним контейнером у підсистемі. Цей шаблон бічного контейнера розширює та покращує функціональність поточних контейнерів без їх зміни. На сьогоднішній день ми знаємо, що ми використовуємо технологію контейнерів для упакування всіх залежностей для запуску додатка в будь-якому місці. Контейнер робить лише одну річ і робить це дуже добре.

  • Майстер-процес:

  • Сервер API (Api Server): Це спосіб, яким користувачі та підсистеми взаємодіють з майстер-процесом. Повинні допускатися лише аутентифіковані запити.

  • Планувальник (Scheduler): Планування означає переконання, що Підсистеми відповідають Вузлам, щоб Kubelet міг їх запустити. Він має достатньо інтелекту, щоб вирішити, який вузол має більше доступних ресурсів, і призначити нову підсистему для нього. Зверніть увагу, що планувальник не запускає нові підсистеми, він просто взаємодіє з процесом Kubelet, який працює всередині вузла, який запустить нову підсистему.

  • Менеджер контролера Kubernetes (Kube Controller manager): Він перевіряє ресурси, такі як набори реплік або розгортки, щоб переконатися, наприклад, що правильна кількість підсистем або вузлів працює. У разі відсутності підсистеми він буде спілкуватися з планувальником, щоб запустити нову. Він контролює реплікацію, токени та облікові послуги для API.

  • etcd: Зберігання даних, постійне, послідовне та розподілене. Це база даних Kubernetes та сховище ключ-значення, де воно зберігає повний стан кластерів (кожна зміна реєструється тут). Компоненти, такі як Планувальник або Менеджер контролера, залежать від цих даних, щоб знати, які зміни відбулися (доступні ресурси вузлів, кількість запущених підсистем...).

  • Менеджер контролера хмарних служб (Cloud controller manager): Це конкретний контролер для керування потоками та додатками, наприклад: якщо у вас є кластери в AWS або OpenStack.

Зверніть увагу, що оскільки може бути кілька вузлів (що запускають кілька підсистем), може бути кілька майстер-процесів, доступ до яких до сервера API балансується та їх etcd синхронізований.

Томи (Volumes):

Коли підсистема створює дані, які не повинні бути втрачені при зникненні підсистеми, їх слід зберігати на фізичному томі. Kubernetes дозволяє прикріплювати том до підсистеми для збереження даних. Том може бути на локальній машині або на віддаленому сховищі. Якщо ви запускаєте підсистеми на різних фізичних вузлах, вам слід використовувати віддалене сховище, щоб всі підсистеми могли до нього звертатися.

Інші конфігурації:

  • ConfigMap: Ви можете налаштувати URL-адреси для доступу до служб. Підсистема отримає дані звідси, щоб знати, як спілкуватися з іншими службами (підсистемами). Зверніть увагу, що це не рекомендоване місце для зберігання облікових даних!

  • Secret: Це місце для зберігання секретних даних, таких як паролі, ключі API... закодовані в B64. Підсистема зможе отримати доступ до цих даних для використання необхідних облікових даних.

  • Розгортки (Deployments): Тут вказуються компоненти, які мають бути запущені Kubernetes. Користувач зазвичай не буде працювати безпосередньо з підсистемами, підсистеми абстраговані від Наборів реплік (кількість однакових реплік підсистем), які запускаються через розгортки. Зверніть увагу, що розгортки призначені для безстандартних додатків. Мінімальна конфігурація для розгортки - це ім'я та зображення для запуску.

  • Набір реплік зі станом (StatefulSet): Цей компонент призначений спеціально для додатків, таких як бази даних, які потребують доступу до одного сховища.

  • Вхід (Ingress): Це конфігурація, яка використовується для викладення додатка публічно за допомогою URL-адреси. Зверніть увагу, що це також можна зробити за допомогою зовнішніх служб, але це правильний спосіб викладення додатка.

  • Якщо ви реалізуєте вхід, вам потрібно створити Контролери входу (Ingress Controllers). Контролер входу - це підсистема, яка буде кінцевою точкою, яка отримає запити, перевірить їх та розподілить навантаження на служби. контролер входу надішле запит на основі налаштованих правил входу. Зверніть увагу, що правила входу можуть вказувати на різні шляхи або навіть піддомені до різних внутрішніх служб Kubernetes.

  • Кращою практикою з точки зору безпеки буде використання хмарного балансувальника навантаження або проксі-сервера як точки входу, щоб не мати жодної частини кластера Kubernetes відкритою.

  • Коли отримано запит, який не відповідає жодному правилу входу, контролер входу направить його до "Стандартного фонового процесу". Ви можете використовувати describe, щоб отримати адресу цього параметра.

  • minikube addons enable ingress

Інфраструктура PKI - Сертифікаційний орган CA:

  • CA є довіреним коренем для всіх сертифікатів всередині кластера.

  • Дозволяє компонентам перевіряти один одного.

  • Усі сертифікати кластера підписані CA.

  • ETCd має власний сертифікат.

  • типи:

    • сертифікат apiserver.

    • сертифікат kubelet.

    • сертифікат планувальника.

Основні дії

Minikube

Minikube може бути використаний для виконання швидких тестів на Kubernetes без необхідності розгортання всього середовища Kubernetes. Він запустить процеси майстра та вузла на одній машині. Minikube використовуватиме virtualbox для запуску вузла. Див. тут, як його встановити.

$ 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

Kubectl - це інструмент командного рядка для кластерів Kubernetes. Він взаємодіє з Api-сервером головного процесу для виконання дій в Kubernetes або для запиту даних.

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

Інтерфейс дозволяє вам легше бачити, що запущено в minikube, ви можете знайти URL для доступу до нього в:

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

Кожен файл конфігурації має 3 частини: метадані, специфікація (що потрібно запустити), стан (бажаний стан). У межах специфікації файлу конфігурації розгортання можна знайти шаблон, визначений новою структурою конфігурації, що визначає зображення для запуску:

Приклад розгортання + Сервіс, визначені в одному файлі конфігурації (з тут)

Оскільки сервіс зазвичай пов'язаний з одним розгортанням, можна визначити обидва в одному файлі конфігурації (сервіс, визначений у цьому конфігураційному файлі, доступний лише в межах системи):

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

Приклад конфігурації зовнішнього сервісу

Цей сервіс буде доступний зовні (перевірте атрибути nodePort та type: LoadBlancer):

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

Це корисно для тестування, але для продакшну вам слід мати лише внутрішні сервіси та Ingress для викладення додатку.

Приклад файлу конфігурації Ingress

Це викладе додаток за адресою 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

Приклад файлу конфігурації секретів

Зверніть увагу, як паролі закодовані у B64 (що не є безпечним!)

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

Приклад ConfigMap

ConfigMap - це конфігурація, яка надається капсулам, щоб вони знали, як знаходити та отримувати доступ до інших служб. У цьому випадку кожна капсула буде знати, що ім'я mongodb-service є адресою капсули, з якою вони можуть спілкуватися (ця капсула буде виконувати mongodb):

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

Потім, всередині конфігурації розгортання цю адресу можна вказати наступним чином, щоб вона була завантажена всередині середовища контейнера:

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

Приклад конфігурації обсягу

Ви можете знайти різні приклади файлів конфігурації зберігання у https://gitlab.com/nanuchi/youtube-tutorial-series/-/tree/master/kubernetes-volumes. Зверніть увагу, що обсяги не знаходяться всередині просторів імен

Простори імен

Kubernetes підтримує кілька віртуальних кластерів, що підтримуються тим самим фізичним кластером. Ці віртуальні кластери називаються просторами імен. Вони призначені для використання в середовищах з багатьма користувачами, розподіленими по різним командам або проектам. Для кластерів з кількома десятками користувачів вам не потрібно створювати або думати про простори імен. Ви повинні почати використовувати простори імен, щоб мати кращий контроль та організацію кожної частини застосунку, розгорнутої в Kubernetes.

Простори імен надають область для імен. Імена ресурсів повинні бути унікальними всередині простору імен, але не між просторами імен. Простори імен не можуть бути вкладені один в одного, і кожен ресурс Kubernetes може бути лише в одному просторі імен.

За замовчуванням є 4 простори імен, якщо ви використовуєте 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: Це не призначено для використання користувачами і ви не повинні до нього торкатися. Це для процесів майстра та kubectl.

  • kube-public: Глобально доступні дані. Містить configmap, який містить інформацію про кластер.

  • kube-node-lease: Визначає доступність вузла.

  • default: Простір імен, який користувач використовуватиме для створення ресурсів.

#Create namespace
kubectl create namespace my-namespace

Зверніть увагу, що більшість ресурсів Kubernetes (наприклад, pods, services, replication controllers та інші) знаходяться в певних просторах імен. Однак інші ресурси, такі як ресурси простору імен та ресурси низького рівня, такі як вузли та persistenVolumes, не знаходяться в просторі імен. Щоб переглянути, які ресурси Kubernetes знаходяться в просторі імен, а які - ні:

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

Ви можете зберегти простір імен для всіх наступних команд kubectl в цьому контексті.

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

Helm

Helm - це менеджер пакетів для Kubernetes. Він дозволяє упаковувати файли YAML та розповсюджувати їх у публічних та приватних репозиторіях. Ці пакети називаються Helm Charts.

helm search <keyword>

Helm - це також шаблонний двигун, який дозволяє генерувати файли конфігурації змінними:

Секрети Kubernetes

Секрет - це об'єкт, який містить чутливі дані, такі як пароль, токен або ключ. Таку інформацію можна було б вказати в специфікації Pod або в зображенні. Користувачі можуть створювати секрети, і система також створює секрети. Ім'я об'єкта Secret повинно бути дійсним ім'ям DNS-піддомену. Прочитайте тут офіційну документацію.

Секрети можуть бути такими речами як:

  • API, SSH-ключі.

  • Токени OAuth.

  • Облікові дані, паролі (звичайний текст або b64 + шифрування).

  • Інформація або коментарі.

  • Код підключення до бази даних, рядки... .

Є різні типи секретів в Kubernetes

Вбудований типВикористання

Opaque

довільні дані, визначені користувачем (за замовчуванням)

kubernetes.io/service-account-token

токен облікового запису служби

kubernetes.io/dockercfg

серіалізований файл ~/.dockercfg

kubernetes.io/dockerconfigjson

серіалізований файл ~/.docker/config.json

kubernetes.io/basic-auth

облікові дані для базової аутентифікації

kubernetes.io/ssh-auth

облікові дані для SSH-аутентифікації

kubernetes.io/tls

дані для TLS-клієнта або сервера

bootstrap.kubernetes.io/token

дані токена запуску

Тип Opaque є типом за замовчуванням, типова пара ключ-значення, визначена користувачем.

Як працюють секрети:

Наступний файл конфігурації визначає секрет під назвою mysecret з 2 парами ключ-значення username: YWRtaW4= та password: MWYyZDFlMmU2N2Rm. Він також визначає под під назвою secretpod, який матиме username та password, визначені в mysecret, викладені в змінних середовища SECRET_USERNAME та SECRET_PASSWOR. Також буде підключено секрет username всередині mysecret за шляхом /etc/foo/my-group/my-username з дозволами 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

Секрети в etcd

etcd - це послідовний та високодоступний сховище ключ-значення, яке використовується як сховище даних кластера Kubernetes. Давайте отримаємо доступ до секретів, збережених в etcd:

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

Ви побачите сертифікати, ключі та URL-адреси, які знаходяться в файловій системі. Як тільки ви отримаєте цю інформацію, ви зможете підключитися до 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

Після встановлення зв'язку ви зможете отримати секрети:

#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

Додавання шифрування до ETCD

За замовчуванням всі секрети зберігаються у відкритому тексті всередині etcd, якщо ви не застосуєте шар шифрування. Наведений нижче приклад базується на 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: {}

Після цього вам потрібно встановити прапор --encryption-provider-config на kube-apiserver, щоб вказати місце розташування створеного файлу конфігурації. Ви можете змінити /etc/kubernetes/manifest/kube-apiserver.yaml та додати наступні рядки:

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

Прокрутіть вниз у розділі volumeMounts:

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

Прокрутіть вниз у volumeMounts до hostPath:

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

Перевірка шифрування даних

Дані шифруються при записі в etcd. Після перезапуску вашого kube-apiserver, будь-який новостворений або оновлений секрет повинен бути зашифрованим при зберіганні. Щоб перевірити, ви можете використовувати командний рядок програми etcdctl, щоб отримати вміст вашого секрету.

  1. Створіть новий секрет під назвою secret1 в просторі імен default:

kubectl create secret generic secret1 -n default --from-literal=mykey=mydata
  1. Використовуючи командний рядок etcdctl, прочитайте цей секрет з etcd:

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

де [...] повинні бути додаткові аргументи для підключення до сервера etcd. 3. Перевірте, що збережений секрет починається з k8s:enc:aescbc:v1:, що вказує на те, що провайдер aescbc зашифрував отримані дані. 4. Перевірте, що секрет правильно розшифровується при отриманні через API:

kubectl describe secret secret1 -n default

повинно відповідати mykey: bXlkYXRh, mydata закодовано, перевірте розкодування секрету, щоб повністю розкодувати секрет.

Оскільки секрети шифруються при записі, виконання оновлення секрету зашифрує це вміст:

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

Останні поради:

Посилання

Вивчайте хакінг AWS від нуля до героя з htARTE (HackTricks AWS Red Team Expert)!

Інші способи підтримки HackTricks:

Last updated