This is an old revision of the document!
kube1:~# cat ~/.kube/config kube1:~# echo LS0tLS1CR...LS0tLS0K | base64 -d
kube1:~# kubectl auth whoami
kube1:~/users# kubectl delete clusterrolebindings admin-user kube1:~/users# kubectl delete serviceaccounts admin-user user1@client1:~$ rm -rf .kube/
kube1:~/users# kubectl -n my-ns describe pod my-debian | grep -i account kube1:~/users# kubectl -n my-ns exec -ti pods/my-debian -- bash root@my-debian:/# apt update && apt install kubectl
kube1:~/users# kubectl auth can-i get pods --as=system:serviceaccount:my-ns:default kube1:~/users# cat sa-default-cluster-admin.yaml
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: sa-default-cluster-admin subjects: - kind: ServiceAccount name: default namespace: my-ns roleRef: kind: ClusterRole name: cluster-admin apiGroup: rbac.authorization.k8s.io
kube1:~/users# kubectl apply -f sa-default-cluster-admin.yaml
Проверяем доступ к API из приложения
kube1:~/users# kubectl delete -f sa-default-cluster-admin.yaml kube1:~/users# kubectl -n my-ns delete pod my-debian
kube1:~/users# vim /etc/kubernetes/manifests/kube-apiserver.yaml
...
spec:
containers:
- command:
- kube-apiserver
- --oidc-issuer-url=https://keycloak.corpX.un/realms/corpX
#- --oidc-client-id=account
- --oidc-client-id=any-client
- --oidc-username-claim=email
#- --oidc-username-claim=preferred_username
- --oidc-groups-claim=groups
...
kube1:~# ps ax | grep kube-apiserver kube1:~/users# kubectl -n kube-system logs Pod/kube-apiserver-kube1 ... E1203 05:22:46.412571 1 authentication.go:73] "Unable to authenticate the request" err="[invalid bearer token, oidc: verify token: oidc: expected audience \"any-client\" got [\"account\"]]" ... E1218 10:36:21.105422 1 authentication.go:75] "Unable to authenticate the request" err="[invalid bearer token, oidc: email not verified]" ...
user1@client1:~$ kubelogin user1@client1:~$ kubectl auth whoami
user1@client1:~$ rm -v user1* user1@client1:~$ rm -rfv .kube/ kube1:~# rm -rfv users/
https://habr.com/ru/companies/slurm/articles/711868/|Журналы аудита Kubernetes: лучшие практики и настройка
kube1:~# cat /etc/kubernetes/audit-policy.yaml
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: None
verbs: ["get", "watch", "list"]
- level: None
resources:
- group: "" # core
resources: ["events"]
- level: None
users:
- "system:kube-scheduler"
- "system:kube-proxy"
- "system:apiserver"
- "system:kube-controller-manager"
- "system:serviceaccount:gatekeeper-system:gatekeeper-admin"
- level: None
userGroups: ["system:nodes"]
- level: RequestResponse
kube1:~# kubectl apply -f /etc/kubernetes/audit-policy.yaml --dry-run=client
error: resource mapping not found for name...
https://kubernetes.io/docs/tasks/debug/debug-cluster/audit/|Kubernetes Documentation - Auditing
kube1:~# vim /etc/kubernetes/manifests/kube-apiserver.yaml
...
- --audit-log-maxage=1
...
kube1:~# date
kube1:~# journalctl -u kubelet --since "2025-12-01 10:19:00" | cat | less
...
..."SyncLoop REMOVE" source="file" pods=["kube-system/kube-apiserver-kube1"]...
...
..."Killing container with a grace period" pod="kube-system/kube-apiserver-kube1"...
kube1:~# tail -f /var/log/kubernetes/audit/audit.log | jq
user1@client1:~$ kubectl -n my-apwebd-ns delete pod my-webd-<TAB>
Создаём группы и пользователей под Kubernetes
У нас уже есть настроенная Freeipa
FreeIPA — это серверная система для централизованного управления пользователями, группами, доступами, сертификатами и DNS в инфраструктуре.
Заходим на freeipa, через web интерфейс или же можно воспользоваться консолью
https://ipa-server-1.teach.local/
ssh root@192.168.100.252
Мы воспользуемся консолью чтобы сэкономить время
Но предварительно на web проверим что нет групп для кубернетис
Используем команду kinit чтобы получить билет Kerberos и введем команды для создания
ipa group-add k8s-cluster-admins \
--desc="Kubernetes cluster admins"
ipa group-add k8s-ns-core-test-view \
--desc="View access to core-test namespace"
ipa group-add k8s-ns-core-test-admin \
--desc="Admin access to core-test namespace"
ipa group-add k8s-ns \
--desc="Access only view all ns"
Теперь обновим страницу с группами и увидим созданные нами группы
Далее Создаём тестового пользователя
ipa user-add ivan \
--first=Ivan \
--last=Petrov \
--password
ipa user-add sergey \
--first=Sergey \
--last=Admin \
--password
ipa user-add kirill \
--first=Kirill \
--last=Viewer \
--password
ipa user-add ira \
--first=Irina\
--last=Viewer \
--password
Далее попросят ввести пароль
Вводим пароль 123456
И подтверждаем
Конечно такой пароль только для демонстрации а не для продового использования
Добавляем пользователя в группу
ipa group-add-member k8s-ns-core-test-view --users=ivan
ipa group-add-member k8s-ns-core-test-admin --users=kirill
ipa group-add-member k8s-ns --users=ira
ipa group-add-member k8s-cluster-admins --users=sergey
Далее Аккаунт для Dex в FreeIPA (LDAP bind user)
Dex должен логиниться в LDAP FreeIPA с каким-то пользователем.
ipa user-add dex-bind \
--first=Dex \
--last=Bind \
--password
Проверяем LDAP-доступ к FreeIPA
Чтобы убедится что dex сможет залогинется
Зайдем на сервер c которого будем управлять k8s и выполнил поиск нашего пользователя
ssh root@192.168.100.249
ldapsearch -x -H ldap://192.168.100.252:389 -D "uid=dex-bind,cn=users,cn=accounts,dc=teach,dc=local" -W -b "cn=users,cn=accounts,dc=teach
,dc=local" "(uid=ivan)"
Подключимся пользователем dex-bind
И поищем созданного нами пользователя ivan
Видим что все ок данные получаем
Далее настроим установим и настроим dex
Для этого будем использовать helm
Helm — это менеджер пакетов для Kubernetes, грубо говоря:
«apt/yum для Kubernetes
Нам понадобится серт мэнеджер для выпуска сетификатов и ингресс контроллер
helm repo add jetstack https://charts.jetstack.io
helm repo update
helm install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--set crds.enabled=true
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install ingress-nginx ingress-nginx/ingress-nginx \
-n ingress-nginx --create-namespace \
--set controller.ingressClassResource.name=nginx \
--set controller.ingressClassByName=true \
--set controller.hostNetwork=true \
--set controller.dnsPolicy=ClusterFirstWithHostNet \
--set controller.kind=DaemonSet \
--set controller.service.type=NodePort
Перезагружаем сервера
Начиная с новых версий FreeIPA, в нём есть ACME-сервер
ACME-server — это “серверная сторона автоматики сертификатов”.
ACME (Automatic Certificate Management Environment) — это протокол, по которому:
клиент (cert-manager, acme.sh, lego, certbot и т.п.)
общается с CA (центром сертификации) через ACME-server
чтобы автоматически выпускать и обновлять TLS-сертификаты.
Примеры ACME-серверов:
Let’s Encrypt (самый известный; их сервер — Boulder)
ipa-acme-manage enable
ipa-acme-manage status
появится эндпоинт
https://ipa-server-1.teach.local/acme/directory
curl -vk https://ipa-server-1.teach.local/acme/directory
далее получаем сертифкат freeipa корневой
идем на сервер freeipa
sudo cat /etc/ipa/ca.crt > ipa-ca.crt
далее переводим в base64
base64 -w0 ipa-ca.crt > ipa-ca.b64
затем нам нужен ClusterIssuer
ClusterIssuer — это кластерный “поставщик сертификатов” в cert-manager, который виден во всех неймспейсах Kubernetes.
Говоря по-человечески:
cert-manager — это оператор, который умеет автоматически выпускать и обновлять сертификаты.
ClusterIssuer/Issuer — это “настройка, куда идти за сертификатом и как его получать”.
Файл issuser.txt
И caBundle ПОДСТАВЬ_ЗДЕСЬ_СТРОКУ_ИЗ_ipa-ca.b64
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: freeipa-acme
spec:
acme:
email: admin@teach.local
server: https://ipa-server-1.teach.local/acme/directory
privateKeySecretRef:
name: freeipa-acme-account-key
# ВАЖНО: одна длинная строка из ipa-ca.b64
caBundle: ПОДСТАВЬ_ЗДЕСЬ_СТРОКУ_ИЗ_ipa-ca.b64
solvers:
- http01:
ingress:
ingressClassName: nginx
1. Выпускаем сертификат для Dex
Сделаем Certificate, который:
использует твой ClusterIssuer freeipa-acme;
кладёт сертификат в Secret dex-tls в namespace dex.
Для начала нам нужна dns запись
Посмотрим какие ip у серверов k8s
kubectl get nodes -o wide
В freeipa
ipa dnsrecord-add teach.local dex --a-rec=192.168.100.229
это адрес одной из наших нод
Создаем нейаспейс
kubectl create ns dex
затем применяем файл с запросом сетификата
файл certificate.txt
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: dex-cert
namespace: dex
spec:
secretName: dex-tls
dnsNames:
- dex.teach.local
issuerRef:
name: freeipa-acme
kind: ClusterIssuer
Добавляем репозиторий с dex
helm repo add dex https://charts.dexidp.io
helm repo update
Качаем локально хелм чарт
helm pull dex/dex
У нас скачивается архив с helm чартом
ls
далее распаковываем архив
tar -xvf dex-0.24.0.tgz
переходим в каталог
cd dex
и тут нас интересует файл values.yaml
vi values.yml
открываем файл и редактируем берем пример из файла config.txt
нужно сгенерить секрет
openssl rand -hex 32
и заменить SUPER-SECRET-STRING на полученный секрет
Создаем секрет
kubectl -n dex create secret generic dex-ldap-bind \
--from-literal=DEX_LDAP_BIND_DN='uid=dex-bind,cn=users,cn=accounts,dc=teach,dc=local' \
--from-literal=DEX_LDAP_BIND_PW='123456'
сохраняем и применяем
helm upgrade --install dex . -n dex -f values.yaml
Тест с любой машины, где dex.teach.local резолвится в IP ноды:
curl -vk https://dex.teach.local/dex/.well-known/openid-configuration
Кладём CA FreeIPA на мастер
Переходим на мастер ноду
ssh root@192.168.100.230
scp root@ipa-server-1.teach.local:/etc/ipa/ca.crt /root/ipa-ca.crt
sudo cp /root/ipa-ca.crt /etc/kubernetes/ssl/dex-ca.crt
Затем правим настройки kubeapi
vi /etc/kubernetes/manifests/kube-apiserver.yaml
Добавляем
- --oidc-issuer-url=https://dex.teach.local/dex
- --oidc-client-id=dex-k8s-authenticator
- --oidc-username-claim=email
- --oidc-groups-claim=groups
- --oidc-ca-file=/etc/kubernetes/ssl/dex-ca.crt
Kubeapi сам перезагрузится
Если все ок то в браузере перейдя по ссылке увидим ответ от dex
https://dex.teach.local/dex/.well-known/openid-configuration
отлично dex установлен но Dex сам по себе — только (OIDC-провайдер).
Страничку, где после логина рисуется готовый kubeconfig, делает другой сервис — dex-k8s-authenticator.
kubectl create namespace dex-auth
Добавляем на freeipa dns запись
ipa dnsrecord-add teach.local auth --a-ip-address=192.168.100.229
ipa dnsrecord-show teach.local auth
выпускаем сертификат для web интерфейса
kubectl apply -f ../certificate-auth.yaml
Ставим dex-k8s-authenticator
helm repo add wiremind https://wiremind.github.io/wiremind-helm-charts
helm repo update
helm pull wiremind/dex-k8s-authenticator
tar -xvf dex-k8s-authenticator-1.7.0.tgz
cd dex-k8s-authenticator
vi values.yaml
в вэлюсах указываем наши данные
вначале копируем содержимое файла certificate-auth.txt
secret: тут должен совпадать с секретов в values dex
далее добавить CA Freeipa в файл конфига
caCerts:
enabled: true
secrets:
- name: ipa-ca
filename: ipa-ca.crt
value: |-
идем на сервер Freeipa
выполняем команду чтобы получить серт в base64
cat /etc/ipa/ca.crt | base64 -w0 > ipa-ca.b64
в k8s_ca_pem:
указываем CA кубернетис
идем на ноду мастера k8s
cat /etc/kubernetes/ssl/ca.crt
helm upgrade --install dex-auth . -n dex-auth -f values.yaml
Теперь нас необходимо связать группы в k8s и freeipa
Применяем манифесты для добавления кластер ролей
kubectl create ns core-test-admin
kubectl create ns core-test-view
проверяем заходим на https://auth.teach.local/
пробуем залогинится под польз кто админ
Заходим на другой сервер и проверяем команды которые нам дал dex
ssh root@192.168.100.227
Вводим команды из web интерфейса
И пробуем подключиться
Далее запускаем тестовые поды в наших ns
Применяем файл test-pod.txt
И тестируем права
Пробуем заходить разными польз
Если не пускает польз когда у него права только на один ns то надо дать права на просмотр.
=== role.txt ===
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: k8s-admins
subjects:
- kind: Group
name: k8s-cluster-admins # ИМЯ ГРУППЫ из FreeIPA
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
---
# 1) Админы НС core-test-admin
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: core-test-admin-admins
namespace: core-test-admin
subjects:
- kind: Group
name: k8s-ns-core-test-admin # ГРУППА из токена Dex / FreeIPA
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: admin # встроенная роль с полным доступом в ns
apiGroup: rbac.authorization.k8s.io
---
# 2) Вьюеры НС core-test-view
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: core-test-view-viewers
namespace: core-test-view
subjects:
- kind: Group
name: k8s-ns-core-test-view # ГРУППА для read-only в этом ns
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: view # встроенная read-only роль для ns
apiGroup: rbac.authorization.k8s.io
---
# 3) Read-only по всему кластеру для группы k8s-ns
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: k8s-ns-read-all
subjects:
- kind: Group
name: k8s-ns # ГРУППА "общие зрители k8s"
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: view # cluster-wide view
apiGroup: rbac.authorization.k8s.io
kubectl apply -f k8s-admins-rbac.yaml
kubectl get clusterrolebinding k8s-admins -o yaml
=== issuer.txt ===
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: freeipa-acme
spec:
acme:
email: admin@teach.local
server: https://ipa-server-1.teach.local/acme/directory
privateKeySecretRef:
name: freeipa-acme-account-key
# ВАЖНО: одна длинная строка из ipa-ca.b64
caBundle: ПОДСТАВЬ_ЗДЕСЬ_СТРОКУ_ИЗ_ipa-ca.b64
solvers:
- http01:
ingress:
ingressClassName: nginx
=== dex-auth-values.txt ===
global:
deployEnv: dev
image:
repository: mintel/dex-k8s-authenticator
tag: 1.4.0
pullPolicy: Always
dexK8sAuthenticator:
port: 5555
debug: true
web_path_prefix: /
clusters:
- name: teach-cluster
short_description: "Учебный кластер"
description: "Kubespray кластер teach.local"
# ДОЛЖНО совпадать с issuer у Dex и --oidc-issuer-url у kube-apiserver
issuer: https://dex.teach.local/dex
# Адрес API-сервера кластера
k8s_master_uri: https://192.168.100.230:6443
# Те же client_id / secret, что в staticClients Dex
client_id: dex-k8s-authenticator
client_secret: 9f3b2e3a7a8d14d0a5ff4b1b8e92c3de0b6b7f21a4e59bd8c1f3d2e7c8a9b0c1
# ДОЛЖНО 1-в-1 совпадать с redirectURIs в Dex для этого клиента
redirect_uri: https://auth.teach.local/callback
k8s_ca_pem: |
-----BEGIN CERTIFICATE-----
ТУТ ЦЕЛИКОМ СОДЕРЖИМОЕ /etc/kubernetes/ssl/ca.crt
БЕЗ base64, как есть
-----END CERTIFICATE-----
service:
type: ClusterIP
port: 5555
ingress:
enabled: true
ingressClassName: nginx
annotations: {}
labels: {}
# В ЭТОМ чарте path один, для всех хостов:
path: /
# hosts — это СПИСОК СТРОК, а не объектов:
hosts:
- auth.teach.local
tls:
- secretName: dex-auth-tls
hosts:
- auth.teach.local
# Чтобы убрать x509: unknown authority для Dex (FreeIPA CA)
caCerts:
enabled: true
secrets:
- name: ipa-ca
filename: ipa-ca.crt
value: |-
ТУТ_ОДНА_СТРОКА_BASE64_ОТ /etc/ipa/ca.crt
=== config.txt ===
replicaCount: 1
image:
repository: ghcr.io/dexidp/dex
tag: v2.44.0
pullPolicy: IfNotPresent
service:
type: ClusterIP
ports:
http:
port: 5556
https:
enabled: false
grpc:
enabled: false
rbac:
create: true
podDisruptionBudget:
enabled: false
networkPolicy:
enabled: false
autoscaling:
enabled: false
ingress:
enabled: true
className: nginx
hosts:
- host: dex.teach.local
paths:
- path: /dex/
pathType: ImplementationSpecific
tls:
- secretName: dex-tls # СЕКРЕТ, который делает cert-manager/FreeIPA
hosts:
- dex.teach.local
configSecret:
create: true
serviceMonitor:
enabled: false
serviceAccount:
create: true # или false, если не нужен отдельный SA
name: "" # пусто = helm сам сгенерит имя по release
annotations: {}
config:
issuer: https://dex.teach.local/dex
storage:
type: kubernetes
config:
inCluster: true
type: memory
web:
http: 0.0.0.0:5556
logger:
level: debug
format: text
oauth2:
skipApprovalScreen: true
staticClients:
- id: example-app
name: Example App
secret: example-app-secret
redirectURIs:
- http://127.0.0.1:5555/callback
- id: dex-k8s-authenticator
name: Dex K8s Authenticator
secret: SUPER-SECRET-STRING
redirectURIs:
- https://auth.teach.local/callback
connectors:
- type: ldap
id: freeipa
name: FreeIPA
config:
host: 192.168.100.252:389
insecureNoSSL: true
startTLS: false
bindDN: "uid=dex-bind,cn=users,cn=accounts,dc=teach,dc=local"
bindPW: "123456"
userSearch:
baseDN: "cn=users,cn=accounts,dc=teach,dc=local"
filter: "(objectClass=person)"
emailAttr: "mail"
idAttr: "uid"
nameAttr: "cn"
username: "uid"
groupSearch:
baseDN: "cn=groups,cn=accounts,dc=teach,dc=local"
filter: "(objectClass=groupofnames)"
userAttr: "dn"
groupAttr: "member"
nameAttr: "cn"
=== certificate-auth.txt ===
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: dex-auth-cert
namespace: dex-auth
spec:
secretName: dex-auth-tls
dnsNames:
- auth.teach.local
issuerRef:
name: freeipa-acme
kind: ClusterIssuer
=== certificate.txt ===
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: dex-cert
namespace: dex
spec:
secretName: dex-tls
dnsNames:
- dex.teach.local
issuerRef:
name: freeipa-acme
kind: ClusterIssuer
=== test-pod.txt ===
apiVersion: v1
kind: Pod
metadata:
name: admin-nginx
namespace: core-test-admin
labels:
app: admin-nginx
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- containerPort: 80
---
apiVersion: v1
kind: Pod
metadata:
name: view-nginx
namespace: core-test-view
labels:
app: view-nginx
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- containerPort: 80