init
This commit is contained in:
81
02-validation/01-resource-validation/README.md
Normal file
81
02-validation/01-resource-validation/README.md
Normal file
@@ -0,0 +1,81 @@
|
||||
# Урок 2.1 — Создание политик валидации ресурсов
|
||||
|
||||
## Файлы
|
||||
|
||||
| Файл | Описание |
|
||||
|------|----------|
|
||||
| `require-resource-limits.yaml` | Обязательные CPU и memory limits |
|
||||
| `disallow-latest-tag.yaml` | Запрет тега :latest |
|
||||
| `allow-only-trusted-registries.yaml` | Только внутренние реестры |
|
||||
| `require-labels.yaml` | Обязательные стандартные лейблы |
|
||||
| `require-min-replicas-production.yaml` | Минимум 2 реплики в production |
|
||||
|
||||
## Применение политик
|
||||
|
||||
```bash
|
||||
# Применить все политики из папки
|
||||
kubectl apply -f .
|
||||
|
||||
# Проверить статус
|
||||
kubectl get clusterpolicies
|
||||
|
||||
# Подробный статус
|
||||
kubectl get clusterpolicies -o wide
|
||||
```
|
||||
|
||||
## Локальное тестирование через Kyverno CLI
|
||||
|
||||
```bash
|
||||
# Протестировать одну политику
|
||||
kyverno apply require-resource-limits.yaml \
|
||||
--resource test-resources/pod-no-limits.yaml
|
||||
|
||||
# Протестировать все политики против всех ресурсов
|
||||
kyverno apply . --resource test-resources/ --table
|
||||
|
||||
# Запустить встроенные тесты
|
||||
kyverno test tests/
|
||||
```
|
||||
|
||||
## Тестирование в кластере
|
||||
|
||||
```bash
|
||||
# Попытка создать под без limits (должна быть ошибка)
|
||||
kubectl apply -f test-resources/pod-no-limits.yaml
|
||||
|
||||
# Создать корректный под
|
||||
kubectl apply -f test-resources/pod-with-limits.yaml
|
||||
|
||||
# Попытка создать под с образом :latest
|
||||
kubectl apply -f test-resources/pod-latest-image.yaml
|
||||
|
||||
# Посмотреть PolicyReport после создания
|
||||
kubectl get policyreports -n default
|
||||
kubectl describe policyreport -n default
|
||||
|
||||
# Найти все нарушения
|
||||
kubectl get policyreports -A -o json | \
|
||||
jq -r '.items[] | .metadata.namespace as $ns |
|
||||
.results[] | select(.result == "fail") |
|
||||
"\($ns)/\(.resources[0].name): \(.policy)/\(.rule): \(.message)"'
|
||||
```
|
||||
|
||||
## Режим Audit — миграция без риска
|
||||
|
||||
```bash
|
||||
# Переключить политику в Audit режим для оценки нарушений
|
||||
kubectl patch clusterpolicy require-resource-limits \
|
||||
--type merge \
|
||||
-p '{"spec":{"validationFailureAction":"Audit"}}'
|
||||
|
||||
# Посмотреть нарушения без блокировки
|
||||
kubectl get policyreports -A -o json | \
|
||||
jq '[.items[].results[] | select(.result == "fail") | .policy] |
|
||||
group_by(.) | map({policy: .[0], violations: length}) |
|
||||
sort_by(-.violations)[]'
|
||||
|
||||
# После исправления — переключить обратно
|
||||
kubectl patch clusterpolicy require-resource-limits \
|
||||
--type merge \
|
||||
-p '{"spec":{"validationFailureAction":"Enforce"}}'
|
||||
```
|
||||
@@ -0,0 +1,51 @@
|
||||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: allow-only-trusted-registries
|
||||
annotations:
|
||||
policies.kyverno.io/title: "Только доверенные реестры"
|
||||
policies.kyverno.io/category: Security
|
||||
policies.kyverno.io/severity: high
|
||||
policies.kyverno.io/subject: Pod
|
||||
policies.kyverno.io/description: >-
|
||||
Разрешает образы только из доверенных реестров компании.
|
||||
Предотвращает использование образов из публичных реестров
|
||||
без проверки безопасности.
|
||||
НАСТРОЙТЕ список разрешённых реестров под вашу инфраструктуру.
|
||||
spec:
|
||||
validationFailureAction: Enforce
|
||||
background: true
|
||||
rules:
|
||||
- name: check-trusted-registries
|
||||
match:
|
||||
resources:
|
||||
kinds:
|
||||
- Pod
|
||||
exclude:
|
||||
resources:
|
||||
namespaces:
|
||||
- kube-system
|
||||
- kyverno
|
||||
validate:
|
||||
message: >-
|
||||
Образ '{{ element.image }}' из недоверенного реестра.
|
||||
Разрешены только:
|
||||
- registry.company.com/
|
||||
- gcr.io/company-project/
|
||||
Загрузите образ в внутренний реестр и обновите манифест.
|
||||
foreach:
|
||||
- list: >-
|
||||
request.object.spec.containers[] |
|
||||
merge(request.object.spec.initContainers[] || `[]`, @)
|
||||
deny:
|
||||
conditions:
|
||||
all:
|
||||
# Образ НЕ из первого доверенного реестра
|
||||
- key: "{{ element.image }}"
|
||||
operator: NotStartsWith
|
||||
value: "registry.company.com/"
|
||||
# И НЕ из второго доверенного реестра
|
||||
- key: "{{ element.image }}"
|
||||
operator: NotStartsWith
|
||||
value: "gcr.io/company-project/"
|
||||
# Добавьте дополнительные условия по аналогии
|
||||
@@ -0,0 +1,44 @@
|
||||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: disallow-latest-tag
|
||||
annotations:
|
||||
policies.kyverno.io/title: "Запрет тега latest"
|
||||
policies.kyverno.io/category: Best Practices
|
||||
policies.kyverno.io/severity: medium
|
||||
policies.kyverno.io/subject: Pod
|
||||
policies.kyverno.io/description: >-
|
||||
Запрещает использование тега :latest и образов без тега.
|
||||
Оба варианта резолвятся в "последний доступный образ",
|
||||
что делает деплойменты невоспроизводимыми.
|
||||
spec:
|
||||
validationFailureAction: Enforce
|
||||
background: true
|
||||
rules:
|
||||
- name: disallow-latest-tag
|
||||
match:
|
||||
resources:
|
||||
kinds:
|
||||
- Pod
|
||||
exclude:
|
||||
resources:
|
||||
namespaces:
|
||||
- kube-system
|
||||
validate:
|
||||
message: >-
|
||||
Образ '{{ element.image }}' использует тег :latest или не имеет тега.
|
||||
Используйте конкретный тег (например, nginx:1.25.3) или digest
|
||||
(nginx@sha256:abc123...) для воспроизводимых деплойментов.
|
||||
foreach:
|
||||
- list: >-
|
||||
request.object.spec.containers[] |
|
||||
merge(request.object.spec.initContainers[] || `[]`, @)
|
||||
deny:
|
||||
conditions:
|
||||
any:
|
||||
- key: "{{ element.image }}"
|
||||
operator: Contains
|
||||
value: ":latest"
|
||||
- key: "{{ element.image }}"
|
||||
operator: NotContains
|
||||
value: ":"
|
||||
46
02-validation/01-resource-validation/require-labels.yaml
Normal file
46
02-validation/01-resource-validation/require-labels.yaml
Normal file
@@ -0,0 +1,46 @@
|
||||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: require-standard-labels
|
||||
annotations:
|
||||
policies.kyverno.io/title: "Обязательные стандартные лейблы"
|
||||
policies.kyverno.io/category: Governance
|
||||
policies.kyverno.io/severity: medium
|
||||
policies.kyverno.io/subject: Deployment,StatefulSet,DaemonSet
|
||||
policies.kyverno.io/description: >-
|
||||
Требует наличия стандартных лейблов у workload ресурсов.
|
||||
Лейблы используются для мониторинга, алертинга и распределения затрат.
|
||||
Допустимые значения environment: dev | staging | production
|
||||
spec:
|
||||
validationFailureAction: Enforce
|
||||
background: true
|
||||
rules:
|
||||
- name: check-required-labels
|
||||
match:
|
||||
resources:
|
||||
kinds:
|
||||
- Deployment
|
||||
- StatefulSet
|
||||
- DaemonSet
|
||||
exclude:
|
||||
resources:
|
||||
namespaces:
|
||||
- kube-system
|
||||
- kyverno
|
||||
validate:
|
||||
message: >-
|
||||
Ресурс '{{ request.object.metadata.name }}' должен иметь лейблы:
|
||||
app, version, team, environment (dev|staging|production)
|
||||
Пример:
|
||||
labels:
|
||||
app: my-service
|
||||
version: "1.0.0"
|
||||
team: payments
|
||||
environment: production
|
||||
pattern:
|
||||
metadata:
|
||||
labels:
|
||||
app: "?*"
|
||||
version: "?*"
|
||||
team: "?*"
|
||||
environment: "^(dev|staging|production)$"
|
||||
@@ -0,0 +1,31 @@
|
||||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: require-min-replicas-production
|
||||
annotations:
|
||||
policies.kyverno.io/title: "Минимальное количество реплик в production"
|
||||
policies.kyverno.io/category: Availability
|
||||
policies.kyverno.io/severity: high
|
||||
policies.kyverno.io/subject: Deployment
|
||||
policies.kyverno.io/description: >-
|
||||
В namespace production требуется минимум 2 реплики для Deployment.
|
||||
Одна реплика = single point of failure при обновлении ноды или пода.
|
||||
spec:
|
||||
validationFailureAction: Enforce
|
||||
background: true
|
||||
rules:
|
||||
- name: check-min-replicas
|
||||
match:
|
||||
resources:
|
||||
kinds:
|
||||
- Deployment
|
||||
namespaces:
|
||||
- production
|
||||
validate:
|
||||
message: >-
|
||||
Deployment '{{ request.object.metadata.name }}' в production
|
||||
имеет {{ request.object.spec.replicas }} реплику(и).
|
||||
Минимально требуется 2 реплики для обеспечения доступности.
|
||||
pattern:
|
||||
spec:
|
||||
replicas: ">=2"
|
||||
@@ -0,0 +1,49 @@
|
||||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: require-resource-limits
|
||||
annotations:
|
||||
policies.kyverno.io/title: "Обязательные resource limits"
|
||||
policies.kyverno.io/category: Resources
|
||||
policies.kyverno.io/severity: high
|
||||
policies.kyverno.io/subject: Pod
|
||||
policies.kyverno.io/description: >-
|
||||
Каждый контейнер (включая init и ephemeral) обязан иметь
|
||||
limits.memory и limits.cpu. Без лимитов контейнер может
|
||||
потребить все ресурсы ноды и убить соседей (noisy neighbor).
|
||||
spec:
|
||||
validationFailureAction: Enforce
|
||||
background: true
|
||||
rules:
|
||||
- name: check-container-limits
|
||||
match:
|
||||
resources:
|
||||
kinds:
|
||||
- Pod
|
||||
exclude:
|
||||
resources:
|
||||
namespaces:
|
||||
- kube-system
|
||||
- kyverno
|
||||
validate:
|
||||
message: >-
|
||||
Контейнер '{{ element.name }}' в поде '{{ request.object.metadata.name }}'
|
||||
(namespace: {{ request.object.metadata.namespace }}) не имеет resource limits.
|
||||
|
||||
Добавьте в манифест:
|
||||
resources:
|
||||
limits:
|
||||
memory: "256Mi"
|
||||
cpu: "500m"
|
||||
|
||||
Документация: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
|
||||
foreach:
|
||||
- list: >-
|
||||
request.object.spec.containers[] |
|
||||
merge(request.object.spec.initContainers[] || `[]`, @) |
|
||||
merge(request.object.spec.ephemeralContainers[] || `[]`, @)
|
||||
pattern:
|
||||
resources:
|
||||
limits:
|
||||
memory: "?*"
|
||||
cpu: "?*"
|
||||
@@ -0,0 +1,19 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: pod-latest-image
|
||||
namespace: default
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:latest # тег :latest — политика отклонит
|
||||
resources:
|
||||
limits:
|
||||
memory: "128Mi"
|
||||
cpu: "100m"
|
||||
- name: redis
|
||||
image: redis # нет тега вообще — тоже отклонит
|
||||
resources:
|
||||
limits:
|
||||
memory: "128Mi"
|
||||
cpu: "100m"
|
||||
@@ -0,0 +1,10 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: pod-no-limits
|
||||
namespace: default
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:1.25.3
|
||||
# нет блока resources — политика require-resource-limits отклонит
|
||||
@@ -0,0 +1,21 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: pod-with-limits
|
||||
namespace: default
|
||||
labels:
|
||||
app: my-app
|
||||
version: "1.0.0"
|
||||
team: platform
|
||||
environment: staging
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:1.25.3 # конкретный тег — хорошо
|
||||
resources:
|
||||
requests:
|
||||
memory: "64Mi"
|
||||
cpu: "50m"
|
||||
limits:
|
||||
memory: "128Mi"
|
||||
cpu: "100m"
|
||||
30
02-validation/01-resource-validation/tests/kyverno-test.yaml
Normal file
30
02-validation/01-resource-validation/tests/kyverno-test.yaml
Normal file
@@ -0,0 +1,30 @@
|
||||
name: resource-validation-tests
|
||||
policies:
|
||||
- ../require-resource-limits.yaml
|
||||
- ../disallow-latest-tag.yaml
|
||||
- ../require-labels.yaml
|
||||
resources:
|
||||
- pod-with-limits.yaml
|
||||
- pod-no-limits.yaml
|
||||
- pod-latest-image.yaml
|
||||
results:
|
||||
- policy: require-resource-limits
|
||||
rule: check-container-limits
|
||||
resource: pod-with-limits
|
||||
namespace: default
|
||||
result: pass
|
||||
- policy: require-resource-limits
|
||||
rule: check-container-limits
|
||||
resource: pod-no-limits
|
||||
namespace: default
|
||||
result: fail
|
||||
- policy: disallow-latest-tag
|
||||
rule: disallow-latest-tag
|
||||
resource: pod-with-limits
|
||||
namespace: default
|
||||
result: pass
|
||||
- policy: disallow-latest-tag
|
||||
rule: disallow-latest-tag
|
||||
resource: pod-latest-image
|
||||
namespace: default
|
||||
result: fail
|
||||
Reference in New Issue
Block a user