This commit is contained in:
2026-04-08 20:22:14 +07:00
commit 34fbdd1412
96 changed files with 5321 additions and 0 deletions

View File

@@ -0,0 +1,75 @@
# Урок 2.2 — Политики безопасности и соответствия стандартам
## Файлы
| Файл | PSS профиль | Описание |
|------|-------------|----------|
| `disallow-privileged-containers.yaml` | Baseline | Запрет `privileged: true` |
| `disallow-dangerous-capabilities.yaml` | Baseline | Запрет опасных capabilities |
| `require-drop-all-capabilities.yaml` | Restricted | Обязательный `drop: [ALL]` |
| `require-run-as-non-root.yaml` | Restricted | Запрет запуска от root |
| `disallow-host-namespaces.yaml` | Baseline | Запрет hostNetwork/PID/IPC/Path |
| `require-seccomp-profile.yaml` | Restricted | Обязательный seccomp |
| `restrict-automount-sa-token.yaml` | CIS | Отключение автомонтирования токена |
## Стратегия внедрения (поэтапно)
### Этап 1 — Аудит (неделя 12)
```bash
# Применить все политики в режиме Audit
for f in *.yaml; do
kubectl apply -f "$f"
done
# Подождать 5 минут для background scan, затем:
kubectl get policyreports -A -o json | \
jq -r '[.items[].results[] | select(.result == "fail") | .policy] |
group_by(.) | map({policy: .[0], count: length}) |
sort_by(-.count)[] | "\(.count)\t\(.policy)"'
```
### Этап 2 — Оценка нарушений
```bash
# Детали нарушений по конкретной политике
POLICY="disallow-privileged-containers"
kubectl get policyreports -A -o json | \
jq --arg p "$POLICY" \
-r '.items[] | .metadata.namespace as $ns |
.results[] | select(.policy == $p and .result == "fail") |
"\($ns)/\(.resources[0].name): \(.message)"'
```
### Этап 3 — Тестирование через Kyverno CLI
```bash
# Проверить под с нарушениями
kyverno apply . \
--resource test-resources/pod-insecure.yaml \
--table
# Проверить корректный под
kyverno apply . \
--resource test-resources/pod-secure.yaml \
--table
```
### Этап 4 — Перевод в Enforce
```bash
# По одной политике
kubectl patch clusterpolicy disallow-privileged-containers \
--type merge \
-p '{"spec":{"validationFailureAction":"Enforce"}}'
```
## Тестовые ресурсы
```bash
# Под с нарушениями (должен быть отклонён)
kubectl apply -f test-resources/pod-insecure.yaml
# Безопасный под (должен пройти)
kubectl apply -f test-resources/pod-secure.yaml
```

View File

@@ -0,0 +1,59 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-dangerous-capabilities
annotations:
policies.kyverno.io/title: "Запрет опасных Linux Capabilities"
policies.kyverno.io/category: Pod Security Standards (Baseline)
policies.kyverno.io/severity: high
policies.kyverno.io/subject: Pod
policies.kyverno.io/description: >-
Запрещает добавление опасных Linux capabilities.
SYS_ADMIN, NET_ADMIN, SYS_PTRACE и другие дают контейнеру
привилегированный доступ к ядру и сети хоста.
Допустима только NET_BIND_SERVICE (порты < 1024).
spec:
validationFailureAction: Enforce
background: true
rules:
- name: disallow-dangerous-capabilities
match:
resources:
kinds:
- Pod
exclude:
resources:
namespaces:
- kube-system
validate:
message: >-
Контейнер '{{ element.name }}' добавляет запрещённые capabilities:
{{ element.securityContext.capabilities.add }}.
Разрешена только NET_BIND_SERVICE.
Пересмотрите необходимость этих привилегий.
foreach:
- list: >-
request.object.spec.containers[] |
merge(request.object.spec.initContainers[] || `[]`, @)
deny:
conditions:
any:
- key: "{{ element.securityContext.capabilities.add[] }}"
operator: AnyIn
value:
- SYS_ADMIN
- NET_ADMIN
- SYS_PTRACE
- SYS_MODULE
- SYS_RAWIO
- SYS_BOOT
- SYS_NICE
- SYS_RESOURCE
- SYS_TIME
- AUDIT_CONTROL
- MAC_ADMIN
- MAC_OVERRIDE
- SETUID
- SETGID
- KILL
- MKNOD

View File

@@ -0,0 +1,57 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-host-namespaces
annotations:
policies.kyverno.io/title: "Запрет host namespaces и HostPath"
policies.kyverno.io/category: Pod Security Standards (Baseline)
policies.kyverno.io/severity: critical
policies.kyverno.io/subject: Pod
policies.kyverno.io/description: >-
hostNetwork, hostPID, hostIPC и hostPath дают контейнеру прямой доступ
к соответствующим ресурсам ноды. Это нарушает изоляцию контейнеров
и является вектором для escape-атак.
spec:
validationFailureAction: Enforce
background: true
rules:
- name: disallow-host-namespaces
match:
resources:
kinds:
- Pod
exclude:
resources:
namespaces:
- kube-system
validate:
message: >-
Под '{{ request.object.metadata.name }}' использует host namespace.
Запрещены: hostNetwork, hostIPC, hostPID.
Эти настройки дают контейнеру доступ к сети/процессам/IPC ноды.
pattern:
spec:
=(hostNetwork): false
=(hostIPC): false
=(hostPID): false
- name: disallow-hostpath-volumes
match:
resources:
kinds:
- Pod
exclude:
resources:
namespaces:
- kube-system
validate:
message: >-
Под '{{ request.object.metadata.name }}' использует HostPath volume.
HostPath даёт контейнеру прямой доступ к файловой системе ноды.
Используйте emptyDir, configMap, secret или PersistentVolumeClaim.
deny:
conditions:
any:
- key: "{{ request.object.spec.volumes[].hostPath | length(@) }}"
operator: GreaterThan
value: "0"

View File

@@ -0,0 +1,43 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-privileged-containers
annotations:
policies.kyverno.io/title: "Запрет привилегированных контейнеров"
policies.kyverno.io/category: Pod Security Standards (Baseline)
policies.kyverno.io/severity: critical
policies.kyverno.io/subject: Pod
policies.kyverno.io/description: >-
Привилегированный контейнер имеет полный доступ к хост-системе —
эквивалент root на самой ноде. Компрометация такого контейнера
означает компрометацию всей ноды.
Проверяются: containers, initContainers, ephemeralContainers.
spec:
validationFailureAction: Enforce
background: true
rules:
- name: privileged-containers
match:
resources:
kinds:
- Pod
exclude:
resources:
namespaces:
- kube-system
validate:
message: >-
Контейнер '{{ element.name }}' имеет securityContext.privileged: true.
Привилегированные контейнеры запрещены — они получают полный доступ к хосту.
Удалите поле securityContext.privileged или установите значение false.
foreach:
- list: >-
request.object.spec.containers[] |
merge(request.object.spec.initContainers[] || `[]`, @) |
merge(request.object.spec.ephemeralContainers[] || `[]`, @)
deny:
conditions:
any:
- key: "{{ element.securityContext.privileged }}"
operator: Equals
value: true

View File

@@ -0,0 +1,41 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-drop-all-capabilities
annotations:
policies.kyverno.io/title: "Обязательный drop ALL capabilities"
policies.kyverno.io/category: Pod Security Standards (Restricted)
policies.kyverno.io/severity: medium
policies.kyverno.io/subject: Pod
policies.kyverno.io/description: >-
Каждый контейнер должен явно сбросить все capabilities через
securityContext.capabilities.drop: [ALL].
Это часть профиля Restricted согласно Pod Security Standards.
spec:
validationFailureAction: Enforce
background: true
rules:
- name: require-drop-all
match:
resources:
kinds:
- Pod
exclude:
resources:
namespaces:
- kube-system
validate:
message: >-
Контейнер '{{ element.name }}' не сбрасывает все capabilities.
Добавьте в securityContext:
capabilities:
drop:
- ALL
foreach:
- list: "request.object.spec.containers"
deny:
conditions:
all:
- key: "ALL"
operator: NotIn
value: "{{ element.securityContext.capabilities.drop[] || `[]` }}"

View File

@@ -0,0 +1,58 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-run-as-non-root
annotations:
policies.kyverno.io/title: "Запрет запуска от root"
policies.kyverno.io/category: Pod Security Standards (Restricted)
policies.kyverno.io/severity: high
policies.kyverno.io/subject: Pod
policies.kyverno.io/description: >-
Контейнеры не должны запускаться от пользователя root (UID 0).
Процесс от root может читать/писать файлы хоста через volume mounts
даже без привилегированного режима.
Установите runAsNonRoot: true или runAsUser >= 1000.
spec:
validationFailureAction: Enforce
background: true
rules:
- name: check-runasnonroot-pod-level
match:
resources:
kinds:
- Pod
exclude:
resources:
namespaces:
- kube-system
validate:
message: >-
Под '{{ request.object.metadata.name }}' должен иметь
spec.securityContext.runAsNonRoot: true.
Это гарантирует, что ни один контейнер не запустится от root.
pattern:
spec:
securityContext:
runAsNonRoot: true
- name: check-runasuser-not-root
match:
resources:
kinds:
- Pod
exclude:
resources:
namespaces:
- kube-system
validate:
message: >-
Контейнер '{{ element.name }}' использует runAsUser: 0 (root).
Установите runAsUser >= 1000.
foreach:
- list: "request.object.spec.containers"
deny:
conditions:
any:
- key: "{{ element.securityContext.runAsUser }}"
operator: Equals
value: 0

View File

@@ -0,0 +1,52 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-seccomp-profile
annotations:
policies.kyverno.io/title: "Обязательный Seccomp профиль"
policies.kyverno.io/category: Pod Security Standards (Restricted)
policies.kyverno.io/severity: medium
policies.kyverno.io/subject: Pod
policies.kyverno.io/description: >-
Seccomp ограничивает системные вызовы контейнера, уменьшая
поверхность атаки на ядро Linux.
Используйте RuntimeDefault (профиль рантайма) или Localhost (кастомный).
spec:
validationFailureAction: Enforce
background: true
rules:
- name: require-seccomp-profile
match:
resources:
kinds:
- Pod
exclude:
resources:
namespaces:
- kube-system
validate:
message: >-
Под '{{ request.object.metadata.name }}' не имеет seccomp профиля.
Добавьте в spec.securityContext:
seccompProfile:
type: RuntimeDefault
pattern:
spec:
securityContext:
seccompProfile:
type: "RuntimeDefault | Localhost"
- name: disallow-unconfined-seccomp
match:
resources:
kinds:
- Pod
validate:
message: >-
Тип Unconfined отключает seccomp защиту. Используйте RuntimeDefault.
deny:
conditions:
any:
- key: "{{ request.object.spec.securityContext.seccompProfile.type }}"
operator: Equals
value: Unconfined

View File

@@ -0,0 +1,37 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: restrict-automount-service-account-token
annotations:
policies.kyverno.io/title: "Ограничение автомонтирования ServiceAccount токена"
policies.kyverno.io/category: Security
policies.kyverno.io/severity: medium
policies.kyverno.io/subject: Pod
policies.kyverno.io/description: >-
По умолчанию Kubernetes монтирует токен ServiceAccount в каждый под.
Если приложение не использует Kubernetes API, этот токен — лишняя
поверхность атаки. CIS Benchmark рекомендует отключать автомонтирование
там, где токен не нужен.
spec:
validationFailureAction: Audit
background: true
rules:
- name: check-automount-service-account
match:
resources:
kinds:
- Pod
exclude:
resources:
namespaces:
- kube-system
validate:
message: >-
Под '{{ request.object.metadata.name }}' автоматически монтирует
ServiceAccount токен (automountServiceAccountToken: true по умолчанию).
Если под не обращается к Kubernetes API, добавьте:
spec:
automountServiceAccountToken: false
pattern:
spec:
automountServiceAccountToken: false

View File

@@ -0,0 +1,21 @@
apiVersion: v1
kind: Pod
metadata:
name: pod-insecure
namespace: default
spec:
hostNetwork: true # нарушение: host namespace
hostPID: true # нарушение: host namespace
containers:
- name: app
image: nginx:1.25.3
securityContext:
privileged: true # нарушение: привилегированный контейнер
runAsUser: 0 # нарушение: запуск от root
capabilities:
add:
- SYS_ADMIN # нарушение: опасная capability
resources:
limits:
memory: "128Mi"
cpu: "100m"

View File

@@ -0,0 +1,28 @@
apiVersion: v1
kind: Pod
metadata:
name: pod-secure
namespace: default
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
seccompProfile:
type: RuntimeDefault
automountServiceAccountToken: false
containers:
- name: app
image: nginx:1.25.3
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
resources:
requests:
memory: "64Mi"
cpu: "50m"
limits:
memory: "128Mi"
cpu: "100m"