← До програми курсу

Модуль 14 / 19

ServiceAccount, RBAC, securityContext, Pod Security та admission

KUBERNETES

Зміст
01

1. Цілі та результат модуля

Ви навчитеся проводити запит через authentication, authorization та admission, видавати workload мінімальні права й застосовувати runtime restrictions без privileged containers.

  • ServiceAccount — identity namespaced workload
  • RBAC дозволяє verbs над resources
  • RoleBinding пов’язує subject і role
  • securityContext обмежує процес
  • Pod Security admission відхиляє небезпечний Pod до запуску
02

2. Теорія: шлях API-запиту

API Server спочатку встановлює identity через authentication, потім authorizer вирішує дію, після чого admission може змінити чи відхилити об’єкт. Успішний RBAC не обходить admission, а Pod Security не видає API-доступ.

  • 401 — credentials не прийнято
  • 403 — identity відома, але дію заборонено
  • 422/Forbidden admission — об’єкт порушує policy
  • Running Pod — результат після admission, scheduling і kubelet
03

3. ServiceAccount і projected token

ServiceAccount — namespaced identity для процесів Pod. Сучасний Pod отримує short-lived projected token з audience і строком, CA bundle та namespace metadata. Старі постійні Secret-токени не слід створювати без причини.

Якщо застосунок не звертається до API, задавайте automountServiceAccountToken: false. Сам token mount не дає прав: їх визначає authorization.

04

4. RBAC і least privilege

Role діє в namespace; ClusterRole описує cluster-scoped або повторно вживаний набір правил. RoleBinding видає Role чи ClusterRole в одному namespace, ClusterRoleBinding — у всьому кластері. Правило задає apiGroups, resources, verbs та інколи resourceNames.

Не використовуйте wildcard і cluster-admin для усунення 403. Визначте точний запит, перевірте kubectl auth can-i та видайте мінімальні права.

05

5. securityContext і Linux controls

runAsNonRoot/runAsUser задають identity процесу; allowPrivilegeEscalation:false блокує додаткові privileges; capabilities.drop видаляє Linux capabilities; readOnlyRootFilesystem захищає root layer; seccomp RuntimeDefault фільтрує syscalls.

Ці налаштування доповнюють image hygiene, filesystem permissions, namespaces, cgroups і LSM. Вони не замінюють NetworkPolicy та RBAC.

06

6. Pod Security admission

Pod Security Standards мають рівні Privileged, Baseline і Restricted. Namespace labels обирають enforce, audit і warn та версію. enforce відхиляє об’єкт; audit записує порушення; warn повідомляє клієнту.

Restricted вимагає non-root intent, заборону privilege escalation, drop ALL capabilities і seccomp profile. Винятки проєктують вузько для системних workloads.

07

7. Методичні вказівки

  • Починайте з identity і точного verb/resource/namespace
  • Перевіряйте can-i під фактичним ServiceAccount
  • Не декодуйте й не друкуйте token
  • Не використовуйте --no-check-certificate для API
  • Вимикайте automount, якщо API не потрібен
  • Застосовуйте restricted context у manifest
  • Розділяйте 401, 403 та admission rejection
  • Не видавайте wildcard без причини
08

8. Лабораторна робота: ServiceAccount і RBAC

Створіть Role лише для читання Pods і доведіть дозволену та заборонену дії через impersonation.

terminal
mkdir -p /tmp/k8s-m14
kubectl create namespace k8s-m14
kubectl label namespace k8s-m14 \
  pod-security.kubernetes.io/enforce=restricted \
  pod-security.kubernetes.io/audit=restricted \
  pod-security.kubernetes.io/warn=restricted
cat > /tmp/k8s-m14/rbac.yaml <<'EOF'
apiVersion: v1
kind: ServiceAccount
metadata: {name: pod-reader, namespace: k8s-m14}
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata: {name: pod-reader, namespace: k8s-m14}
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata: {name: pod-reader, namespace: k8s-m14}
subjects:
- {kind: ServiceAccount, name: pod-reader, namespace: k8s-m14}
roleRef: {apiGroup: rbac.authorization.k8s.io, kind: Role, name: pod-reader}
EOF
kubectl apply --dry-run=server -f /tmp/k8s-m14/rbac.yaml
kubectl apply -f /tmp/k8s-m14/rbac.yaml
kubectl auth can-i list pods --as=system:serviceaccount:k8s-m14:pod-reader -n k8s-m14
kubectl auth can-i get secrets --as=system:serviceaccount:k8s-m14:pod-reader -n k8s-m14
kubectl auth can-i --list --as=system:serviceaccount:k8s-m14:pod-reader -n k8s-m14
09

9. Лабораторна робота: запит із Pod

Restricted Pod використовує projected token і CA для TLS-перевіреного запиту до API. Token не виводиться в термінал.

terminal
cat > /tmp/k8s-m14/client.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata: {name: api-client, namespace: k8s-m14}
spec:
  serviceAccountName: pod-reader
  securityContext:
    runAsNonRoot: true
    runAsUser: 10001
    seccompProfile: {type: RuntimeDefault}
  containers:
  - name: client
    image: curlimages/curl:8.16.0
    command: ["sh", "-c", "sleep 3600"]
    securityContext:
      allowPrivilegeEscalation: false
      readOnlyRootFilesystem: true
      capabilities: {drop: ["ALL"]}
EOF
kubectl apply --dry-run=server -f /tmp/k8s-m14/client.yaml
kubectl apply -f /tmp/k8s-m14/client.yaml
kubectl -n k8s-m14 wait --for=condition=Ready pod/api-client --timeout=180s
kubectl -n k8s-m14 exec api-client -- sh -c '
  token=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
  curl -fsS --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt \
    -H "Authorization: Bearer $token" \
    https://kubernetes.default.svc/api/v1/namespaces/k8s-m14/pods
' | head -c 600
kubectl -n k8s-m14 get pod api-client -o jsonpath='tokenTTL={.spec.volumes[0].projected.sources[0].serviceAccountToken.expirationSeconds}{"\n"}'
10

10. Лабораторна робота: runtime restrictions

Перевірте UID, NoNewPrivs, seccomp і capabilities, потім доведіть read-only root filesystem. Другий Pod не отримує token volume.

terminal
kubectl -n k8s-m14 exec api-client -- id
kubectl -n k8s-m14 exec api-client -- sh -c 'grep -E "^(NoNewPrivs|Seccomp|CapEff):" /proc/1/status'
kubectl -n k8s-m14 exec api-client -- touch /write-test 2>&1 || true
cat > /tmp/k8s-m14/no-token.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata: {name: no-token, namespace: k8s-m14}
spec:
  serviceAccountName: pod-reader
  automountServiceAccountToken: false
  securityContext: {runAsNonRoot: true, runAsUser: 10001, seccompProfile: {type: RuntimeDefault}}
  containers:
  - name: app
    image: busybox:1.37
    command: ["sh", "-c", "sleep 3600"]
    securityContext: {allowPrivilegeEscalation: false, readOnlyRootFilesystem: true, capabilities: {drop: ["ALL"]}}
EOF
kubectl apply -f /tmp/k8s-m14/no-token.yaml
kubectl -n k8s-m14 wait --for=condition=Ready pod/no-token --timeout=120s
kubectl -n k8s-m14 get pod no-token -o jsonpath='{.spec.volumes}{"\n"}'
11

11. Діагностика: admission rejection і RBAC 403

Privileged Pod відхиляється до збереження. Потім API-клієнт отримує HTTP 403 на secrets: це authorization failure, а не TLS чи DNS.

terminal
cat > /tmp/k8s-m14/privileged.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata: {name: privileged-test, namespace: k8s-m14}
spec:
  containers:
  - name: app
    image: busybox:1.37
    command: ["sh", "-c", "sleep 3600"]
    securityContext: {privileged: true}
EOF
kubectl apply --dry-run=server -f /tmp/k8s-m14/privileged.yaml || true
kubectl apply -f /tmp/k8s-m14/privileged.yaml || true
kubectl -n k8s-m14 get pod privileged-test 2>&1 || true
kubectl get namespace k8s-m14 --show-labels
terminal
kubectl -n k8s-m14 exec api-client -- sh -c '
  token=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
  curl -sS -w "\nhttp=%{http_code}\n" \
    --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt \
    -H "Authorization: Bearer $token" \
    https://kubernetes.default.svc/api/v1/namespaces/k8s-m14/secrets
'
kubectl auth can-i get secrets --as=system:serviceaccount:k8s-m14:pod-reader -n k8s-m14
kubectl get role,rolebinding -n k8s-m14 -o yaml

Порядок: endpoint/TLS → authenticated identity → verb/apiGroup/resource/subresource/namespace → binding → admission policy → runtime security.

12

12. Контроль, критерії засвоєння та cleanup

  • Порядок authentication, authorization, admission?
  • Чим 401 відрізняється від 403?
  • ServiceAccount cluster-scoped?
  • Що обмежує audience token?
  • Коли вимикати automount?
  • RoleBinding може зв’язати ClusterRole?
  • Що робить allowPrivilegeEscalation?
  • Навіщо drop ALL?
  • Відмінності enforce/audit/warn?
  • Чому Pod Security не замінює RBAC?
terminal
kubectl delete namespace k8s-m14 --wait=true
rm -rf /tmp/k8s-m14
kubectl get namespace k8s-m14 2>&1 || true

Модуль засвоєно, якщо workload читає Pods, отримує 403 на Secrets, проходить Restricted policy, а privileged manifest відхиляється admission.