Основи Kubernetes
Reading time: 17 minutes
Основи Kubernetes
tip
Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Підтримка HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи Telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на GitHub.
Оригінальний автор цієї сторінки Хорхе (читайте його оригінальну публікацію тут)
Архітектура та основи
Що робить Kubernetes?
- Дозволяє запускати контейнери в контейнерному двигуні.
- Планування дозволяє ефективно виконувати місії контейнерів.
- Підтримує життєздатність контейнерів.
- Дозволяє комунікацію між контейнерами.
- Дозволяє техніки розгортання.
- Обробляє обсяги інформації.
Архітектура
- Вузол: операційна система з подом або подами.
- Под: обгортка навколо контейнера або кількох контейнерів. Под повинен містити лише один додаток (тому зазвичай под запускає лише 1 контейнер). Под є способом, яким Kubernetes абстрагує технологію контейнерів.
- Сервіс: Кожен под має 1 внутрішню IP-адресу з внутрішнього діапазону вузла. Однак його також можна відкрити через сервіс. Сервіс також має IP-адресу і його мета - підтримувати зв'язок між подами, тому якщо один з них вмирає, новий замінник (з іншою внутрішньою IP) буде доступний за тою ж IP-адресою сервісу. Його можна налаштувати як внутрішній або зовнішній. Сервіс також діє як балансувальник навантаження, коли 2 поди підключені до одного сервісу.
Коли сервіс створюється, ви можете знайти кінцеві точки кожного сервісу, запустившиkubectl get endpoints
- Kubelet: Основний агент вузла. Компонент, який встановлює зв'язок між вузлом і kubectl, і може запускати лише поди (через API-сервер). Kubelet не керує контейнерами, які не були створені Kubernetes.
- Kube-proxy: це сервіс, відповідальний за комунікацію (сервіси) між apiserver і вузлом. Основою є IPtables для вузлів. Найбільш досвідчені користувачі можуть встановлювати інші kube-proxy від інших постачальників.
- Контейнер Sidecar: Контейнери Sidecar - це контейнери, які повинні працювати разом з основним контейнером у поді. Цей шаблон Sidecar розширює та покращує функціональність поточних контейнерів без їх зміни. Сьогодні ми знаємо, що використовуємо технологію контейнерів, щоб обернути всі залежності для запуску додатка в будь-якому місці. Контейнер виконує лише одну задачу і робить це дуже добре.
- Головний процес:
- Api Server: Це спосіб, яким користувачі та поди спілкуються з головним процесом. Дозволяються лише автентифіковані запити.
- Планувальник: Планування стосується забезпечення того, щоб поди відповідали вузлам, щоб Kubelet міг їх запускати. Він має достатньо інтелекту, щоб вирішити, який вузол має більше доступних ресурсів, і призначити новий под. Зверніть увагу, що планувальник не запускає нові поди, він лише спілкується з процесом Kubelet, що працює всередині вузла, який запустить новий под.
- Kube Controller manager: Він перевіряє ресурси, такі як набори реплік або розгортання, щоб перевірити, чи, наприклад, працює правильна кількість подів або вузлів. У разі відсутності пода він зв'яжеться з планувальником, щоб запустити новий. Він контролює реплікацію, токени та облікові сервіси для API.
- etcd: Сховище даних, постійне, послідовне та розподілене. Це база даних Kubernetes і сховище ключ-значення, де зберігається повний стан кластерів (кожна зміна тут реєструється). Компоненти, такі як планувальник або менеджер контролера, залежать від цих даних, щоб знати, які зміни відбулися (доступні ресурси вузлів, кількість запущених подів...)
- Cloud controller manager: Це специфічний контролер для управління потоками та додатками, тобто: якщо у вас є кластери в AWS або OpenStack.
Зверніть увагу, що оскільки може бути кілька вузлів (які запускають кілька подів), також може бути кілька головних процесів, доступ до яких до API-сервера балансуватиметься, а їх etcd синхронізуватиметься.
Томи:
Коли под створює дані, які не повинні бути втрачені, коли под зникає, їх слід зберігати в фізичному томі. Kubernetes дозволяє прикріпити том до пода для збереження даних. Том може бути на локальному комп'ютері або в віддаленому сховищі. Якщо ви запускаєте поди на різних фізичних вузлах, вам слід використовувати віддалене сховище, щоб усі поди могли до нього отримати доступ.
Інші конфігурації:
- ConfigMap: Ви можете налаштувати URL-адреси для доступу до сервісів. Под отримає дані звідси, щоб знати, як спілкуватися з іншими сервісами (поди). Зверніть увагу, що це не рекомендоване місце для збереження облікових даних!
- Secret: Це місце для зберігання секретних даних, таких як паролі, API-ключі... закодованих у B64. Под зможе отримати доступ до цих даних, щоб використовувати необхідні облікові дані.
- Deployments: Це місце, де вказуються компоненти, які будуть запущені Kubernetes. Користувач зазвичай не працює безпосередньо з подами, поди абстраговані в ReplicaSets (кількість однакових подів, що реплікуються), які запускаються через розгортання. Зверніть увагу, що розгортання призначені для безстанційних додатків. Мінімальна конфігурація для розгортання - це ім'я та образ для запуску.
- StatefulSet: Цей компонент призначений спеціально для додатків, таких як бази даних, які потребують доступу до одного й того ж сховища.
- Ingress: Це конфігурація, яка використовується для публічного відкриття додатка з URL-адресою. Зверніть увагу, що це також можна зробити за допомогою зовнішніх сервісів, але це правильний спосіб відкрити додаток.
- Якщо ви реалізуєте Ingress, вам потрібно буде створити Ingress Controllers. Ingress Controller - це под, який буде кінцевою точкою, що отримуватиме запити, перевірятиме їх і балансуватиме навантаження на сервіси. Ingress controller надсилатиме запит на основі налаштованих правил ingress. Зверніть увагу, що правила ingress можуть вказувати на різні шляхи або навіть піддомени для різних внутрішніх сервісів Kubernetes.
- Кращою практикою безпеки буде використання хмарного балансувальника навантаження або проксі-сервера як точки входу, щоб жодна частина кластера Kubernetes не була відкрита.
- Коли отримується запит, який не відповідає жодному правилу ingress, контролер ingress направить його на "Default backend". Ви можете
describe
контролер ingress, щоб отримати адресу цього параметра. 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 Dashboard
Дашборд дозволяє вам легше бачити, що виконує 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
note
Це корисно для тестування, але для виробництва у вас повинні бути лише внутрішні сервіси та 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
Тоді, всередині deployment config ця адреса може бути вказана наступним чином, щоб вона завантажувалася в середовище 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
[...]
Приклад конфігурації обсягу
Ви можете знайти різні приклади конфігурації зберігання yaml файлів за посиланням 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: Це не призначено для користувачів, і вам не слід його чіпати. Це для процесів master і kubectl.
- kube-public: Публічно доступні дані. Містить configmap, який містить інформацію про кластер.
- kube-node-lease: Визначає доступність вузла.
- default: Простір імен, який користувач буде використовувати для створення ресурсів.
#Create namespace
kubectl create namespace my-namespace
note
Зверніть увагу, що більшість ресурсів Kubernetes (наприклад, pods, services, replication controllers та інші) знаходяться в деяких просторах імен. Однак інші ресурси, такі як ресурси простору імен та ресурси нижчого рівня, такі як nodes і persistentVolumes, не знаходяться в просторі імен. Щоб побачити, які ресурси Kubernetes є в просторі імен, а які ні:
kubectl api-resources --namespaced=true #В просторі імен
kubectl api-resources --namespaced=false #Не в просторі імен
Ви можете зберегти простір імен для всіх наступних команд kubectl у цьому контексті.
kubectl config set-context --current --namespace=<insert-namespace-name-here>
Helm
Helm - це менеджер пакетів для Kubernetes. Він дозволяє упаковувати YAML файли та розповсюджувати їх у публічних і приватних репозиторіях. Ці пакети називаються Helm Charts.
helm search <keyword>
Helm також є шаблонним двигуном, який дозволяє генерувати конфігураційні файли з змінними:
Kubernetes секрети
Секрет - це об'єкт, який містить чутливі дані, такі як пароль, токен або ключ. Таку інформацію інакше можна було б помістити в специфікацію Pod або в образ. Користувачі можуть створювати Секрети, а система також створює Секрети. Ім'я об'єкта Секрету повинно бути дійсним 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 | дані токена для завантаження |
note
Тип Opaque є типом за замовчуванням, типовою парою ключ-значення, визначеною користувачами.
Як працюють секрети:
Наступний конфігураційний файл визначає секрет під назвою mysecret
з 2 парами ключ-значення username: YWRtaW4=
та password: MWYyZDFlMmU2N2Rm
. Він також визначає pod під назвою secretpod
, який матиме username
та password
, визначені в mysecret
, доступними в змінних середовища SECRET_USERNAME
__ та __ SECRET_PASSWOR
. Він також монтує секрет username
всередині mysecret
за шляхом /etc/foo/my-group/my-username
з правами 0640
.
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
Secrets in 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/
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
для отримання вмісту вашого секрету.
- Створіть новий секрет під назвою
secret1
у просторі іменdefault
:
kubectl create secret generic secret1 -n default --from-literal=mykey=mydata
- Використовуючи командний рядок etcdctl, прочитайте цей секрет з etcd:
ETCDCTL_API=3 etcdctl get /registry/secrets/default/secret1 [...] | hexdump -C
де [...]
повинні бути додаткові аргументи для підключення до сервера etcd.
- Перевірте, що збережений секрет має префікс
k8s:enc:aescbc:v1:
, що вказує на те, що провайдерaescbc
зашифрував отримані дані. - Перевірте, що секрет правильно розшифрований при отриманні через API:
kubectl describe secret secret1 -n default
повинен відповідати mykey: bXlkYXRh
, mydata закодовано, перевірте декодування секрету, щоб повністю декодувати секрет.
Оскільки секрети зашифровані при запису, виконання оновлення секрету зашифрує цей вміст:
kubectl get secrets --all-namespaces -o json | kubectl replace -f -
Останні поради:
- Намагайтеся не зберігати секрети у FS, отримуйте їх з інших місць.
- Перегляньте https://www.vaultproject.io/ для додаткового захисту ваших секретів.
- https://kubernetes.io/docs/concepts/configuration/secret/#risks
- https://docs.cyberark.com/Product-Doc/OnlineHelp/AAM-DAP/11.2/en/Content/Integrations/Kubernetes_deployApplicationsConjur-k8s-Secrets.htm
Посилання
kubesectips v1 | sickrov.github.io
tip
Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Підтримка HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи Telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на GitHub.