init
This commit is contained in:
134
05-variables/01-configmaps/README.md
Normal file
134
05-variables/01-configmaps/README.md
Normal file
@@ -0,0 +1,134 @@
|
||||
# Урок 5.1 — Переменные окружения и ConfigMaps
|
||||
|
||||
## Файлы
|
||||
|
||||
| Файл | Описание |
|
||||
|------|----------|
|
||||
| `kyverno-global-config.yaml` | Централизованный ConfigMap с настройками |
|
||||
| `set-resource-limits-from-config.yaml` | Мутация: лимиты из ConfigMap |
|
||||
| `inherit-namespace-labels.yaml` | Мутация: лейблы из Namespace (через apiCall) |
|
||||
|
||||
## Применение
|
||||
|
||||
```bash
|
||||
# Сначала ConfigMap
|
||||
kubectl apply -f kyverno-global-config.yaml
|
||||
|
||||
# Затем политики
|
||||
kubectl apply -f set-resource-limits-from-config.yaml
|
||||
kubectl apply -f inherit-namespace-labels.yaml
|
||||
```
|
||||
|
||||
## Типы источников переменных в Kyverno
|
||||
|
||||
```yaml
|
||||
# 1. Данные запроса (всегда доступны)
|
||||
{{ request.object.metadata.name }}
|
||||
{{ request.object.metadata.namespace }}
|
||||
{{ request.operation }} # CREATE | UPDATE | DELETE
|
||||
{{ request.userInfo.username }}
|
||||
{{ request.userInfo.groups }}
|
||||
|
||||
# 2. ConfigMap
|
||||
context:
|
||||
- name: myConfig
|
||||
configMap:
|
||||
name: my-config
|
||||
namespace: kyverno
|
||||
# Использование:
|
||||
{{ myConfig.data.my-key }}
|
||||
|
||||
# 3. Прямой API вызов
|
||||
context:
|
||||
- name: nsInfo
|
||||
apiCall:
|
||||
urlPath: "/api/v1/namespaces/{{ request.object.metadata.namespace }}"
|
||||
jmesPath: "metadata.labels"
|
||||
# Использование:
|
||||
{{ nsInfo.environment }}
|
||||
|
||||
# 4. Встроенная переменная
|
||||
context:
|
||||
- name: defaults
|
||||
variable:
|
||||
value:
|
||||
memory: "256Mi"
|
||||
cpu: "250m"
|
||||
# Использование:
|
||||
{{ defaults.memory }}
|
||||
|
||||
# 5. Генерируемые значения
|
||||
{{ random('[0-9]{6}') }} # случайные 6 цифр
|
||||
{{ time_now_utc() }} # текущее UTC время
|
||||
```
|
||||
|
||||
## Тест переменных из ConfigMap
|
||||
|
||||
```bash
|
||||
# Создать под — должны примениться лимиты из ConfigMap
|
||||
kubectl apply -f - <<EOF
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: test-config-vars
|
||||
namespace: default
|
||||
spec:
|
||||
containers:
|
||||
- name: app
|
||||
image: nginx:1.25.3
|
||||
EOF
|
||||
|
||||
# Проверить лимиты
|
||||
kubectl get pod test-config-vars \
|
||||
-o jsonpath='{.spec.containers[0].resources}' | jq .
|
||||
# Ожидаем: limits.memory=512Mi, limits.cpu=500m (из ConfigMap)
|
||||
|
||||
# Изменить дефолты в ConfigMap и подождать ~60 секунд
|
||||
kubectl patch configmap kyverno-global-config -n kyverno \
|
||||
--type merge \
|
||||
-p '{"data":{"default.memory.limit":"1Gi"}}'
|
||||
|
||||
# Новый под получит 1Gi
|
||||
kubectl run test-after-change --image=nginx:1.25.3 --restart=Never
|
||||
kubectl get pod test-after-change \
|
||||
-o jsonpath='{.spec.containers[0].resources.limits.memory}'
|
||||
# Ожидаем: 1Gi
|
||||
|
||||
# Уборка
|
||||
kubectl delete pod test-config-vars test-after-change
|
||||
```
|
||||
|
||||
## Тест наследования лейблов из Namespace
|
||||
|
||||
```bash
|
||||
# Создать namespace с лейблами
|
||||
kubectl create namespace labeled-ns
|
||||
kubectl label namespace labeled-ns environment=production team=backend
|
||||
|
||||
# Создать под в этом namespace
|
||||
kubectl run test-pod --image=nginx:1.25.3 \
|
||||
--restart=Never -n labeled-ns
|
||||
|
||||
# Проверить унаследованные лейблы
|
||||
kubectl get pod test-pod -n labeled-ns \
|
||||
-o jsonpath='{.metadata.labels}' | jq .
|
||||
# Ожидаем: environment=production, team=backend
|
||||
|
||||
kubectl delete pod test-pod -n labeled-ns
|
||||
kubectl delete namespace labeled-ns
|
||||
```
|
||||
|
||||
## Дефолтные значения (защита от отсутствующих полей)
|
||||
|
||||
```yaml
|
||||
# Опасно: упадёт если лейбл не задан
|
||||
{{ request.object.metadata.labels.env }}
|
||||
|
||||
# Безопасно: вернёт "unknown" если лейбл отсутствует
|
||||
{{ request.object.metadata.labels.env || 'unknown' }}
|
||||
|
||||
# Цепочка дефолтов
|
||||
{{ request.object.metadata.labels.region ||
|
||||
globalConfig.data.default_region ||
|
||||
'us-east-1' }}
|
||||
```
|
||||
36
05-variables/01-configmaps/inherit-namespace-labels.yaml
Normal file
36
05-variables/01-configmaps/inherit-namespace-labels.yaml
Normal file
@@ -0,0 +1,36 @@
|
||||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: inherit-namespace-labels
|
||||
annotations:
|
||||
policies.kyverno.io/title: "Наследование лейблов из Namespace"
|
||||
policies.kyverno.io/category: Governance
|
||||
policies.kyverno.io/severity: low
|
||||
policies.kyverno.io/subject: Pod
|
||||
policies.kyverno.io/description: >-
|
||||
Копирует лейблы environment и team из Namespace в Pod.
|
||||
Позволяет автоматически тегировать поды данными их namespace
|
||||
без ручного дублирования в каждом манифесте.
|
||||
spec:
|
||||
rules:
|
||||
- name: copy-namespace-labels
|
||||
match:
|
||||
resources:
|
||||
kinds:
|
||||
- Pod
|
||||
exclude:
|
||||
resources:
|
||||
namespaces:
|
||||
- kube-system
|
||||
- kyverno
|
||||
context:
|
||||
- name: nsLabels
|
||||
apiCall:
|
||||
urlPath: "/api/v1/namespaces/{{ request.object.metadata.namespace }}"
|
||||
jmesPath: "metadata.labels"
|
||||
mutate:
|
||||
patchStrategicMerge:
|
||||
metadata:
|
||||
labels:
|
||||
+(environment): "{{ nsLabels.environment || 'unknown' }}"
|
||||
+(team): "{{ nsLabels.team || 'unknown' }}"
|
||||
27
05-variables/01-configmaps/kyverno-global-config.yaml
Normal file
27
05-variables/01-configmaps/kyverno-global-config.yaml
Normal file
@@ -0,0 +1,27 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: kyverno-global-config
|
||||
namespace: kyverno
|
||||
labels:
|
||||
app: kyverno-config
|
||||
data:
|
||||
# --- Resource defaults ---
|
||||
default.memory.request: "128Mi"
|
||||
default.memory.limit: "512Mi"
|
||||
default.cpu.request: "100m"
|
||||
default.cpu.limit: "500m"
|
||||
|
||||
# --- Registry ---
|
||||
allowed.registries: "registry.company.com,gcr.io/company-project"
|
||||
|
||||
# --- Environment ---
|
||||
production.replicas.minimum: "2"
|
||||
staging.replicas.minimum: "1"
|
||||
|
||||
# --- Required labels (через запятую) ---
|
||||
required.labels: "app,team,environment"
|
||||
|
||||
# --- Node settings ---
|
||||
default.node.type: "standard"
|
||||
default.region: "eu-west-1"
|
||||
@@ -0,0 +1,44 @@
|
||||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: set-resource-limits-from-config
|
||||
annotations:
|
||||
policies.kyverno.io/title: "Resource limits из централизованного ConfigMap"
|
||||
policies.kyverno.io/category: Resources
|
||||
policies.kyverno.io/severity: low
|
||||
policies.kyverno.io/subject: Pod
|
||||
policies.kyverno.io/description: >-
|
||||
Устанавливает дефолтные resource limits из ConfigMap kyverno-global-config.
|
||||
Изменение лимитов для всего кластера — это kubectl edit configmap,
|
||||
а не изменение и деплой политики.
|
||||
spec:
|
||||
rules:
|
||||
- name: set-limits-from-configmap
|
||||
match:
|
||||
resources:
|
||||
kinds:
|
||||
- Pod
|
||||
exclude:
|
||||
resources:
|
||||
namespaces:
|
||||
- kube-system
|
||||
- kyverno
|
||||
context:
|
||||
- name: globalConfig
|
||||
configMap:
|
||||
name: kyverno-global-config
|
||||
namespace: kyverno
|
||||
mutate:
|
||||
foreach:
|
||||
- list: "request.object.spec.containers"
|
||||
patchStrategicMerge:
|
||||
spec:
|
||||
containers:
|
||||
- name: "{{ element.name }}"
|
||||
resources:
|
||||
requests:
|
||||
+(memory): "{{ globalConfig.data.\"default.memory.request\" }}"
|
||||
+(cpu): "{{ globalConfig.data.\"default.cpu.request\" }}"
|
||||
limits:
|
||||
+(memory): "{{ globalConfig.data.\"default.memory.limit\" }}"
|
||||
+(cpu): "{{ globalConfig.data.\"default.cpu.limit\" }}"
|
||||
127
05-variables/02-context/README.md
Normal file
127
05-variables/02-context/README.md
Normal file
@@ -0,0 +1,127 @@
|
||||
# Урок 5.2 — Контекстные данные и информация о кластере
|
||||
|
||||
## Файлы
|
||||
|
||||
| Файл | Описание |
|
||||
|------|----------|
|
||||
| `deployment-freeze-config.yaml` | ConfigMap для управления freeze |
|
||||
| `restrict-deploys-during-freeze.yaml` | Блокировка деплоев во время freeze |
|
||||
| `restrict-privileged-non-admins.yaml` | Привилегии только для admin-групп |
|
||||
|
||||
## Применение
|
||||
|
||||
```bash
|
||||
kubectl apply -f deployment-freeze-config.yaml
|
||||
kubectl apply -f restrict-deploys-during-freeze.yaml
|
||||
kubectl apply -f restrict-privileged-non-admins.yaml
|
||||
```
|
||||
|
||||
## Тест deployment freeze
|
||||
|
||||
```bash
|
||||
# Убедиться что freeze выключен
|
||||
kubectl get configmap deployment-freeze-config -n kyverno \
|
||||
-o jsonpath='{.data.freeze_active}'
|
||||
# Должно быть: false
|
||||
|
||||
# Создать тестовый deployment — должен пройти
|
||||
kubectl create deployment test-deploy \
|
||||
--image=nginx:1.25.3 --replicas=1
|
||||
|
||||
# Активировать freeze
|
||||
kubectl patch configmap deployment-freeze-config -n kyverno \
|
||||
--type merge \
|
||||
-p '{"data":{"freeze_active":"true"}}'
|
||||
|
||||
# Подождать обновления кэша (~60 сек), затем попробовать деплой
|
||||
kubectl create deployment blocked-deploy \
|
||||
--image=nginx:1.25.3 --replicas=1
|
||||
# Ожидаем ошибку: Деплойменты заморожены...
|
||||
|
||||
# Деактивировать freeze
|
||||
kubectl patch configmap deployment-freeze-config -n kyverno \
|
||||
--type merge \
|
||||
-p '{"data":{"freeze_active":"false"}}'
|
||||
|
||||
# Уборка
|
||||
kubectl delete deployment test-deploy 2>/dev/null || true
|
||||
```
|
||||
|
||||
## Доступные контекстные данные запроса
|
||||
|
||||
```yaml
|
||||
# Информация о ресурсе
|
||||
request.object.metadata.name
|
||||
request.object.metadata.namespace
|
||||
request.object.metadata.labels
|
||||
request.object.metadata.annotations
|
||||
|
||||
# Информация об операции
|
||||
request.operation # CREATE | UPDATE | DELETE | CONNECT
|
||||
request.dryRun # true при --dry-run=server
|
||||
|
||||
# Старый объект (только при UPDATE)
|
||||
request.oldObject.spec.replicas
|
||||
|
||||
# Информация о пользователе
|
||||
request.userInfo.username
|
||||
request.userInfo.uid
|
||||
request.userInfo.groups # список групп
|
||||
request.userInfo.extra # дополнительные атрибуты
|
||||
|
||||
# Пример: разные правила для CREATE vs UPDATE
|
||||
preconditions:
|
||||
any:
|
||||
- key: "{{ request.operation }}"
|
||||
operator: Equals
|
||||
value: CREATE
|
||||
```
|
||||
|
||||
## Тест userInfo — проверка групп
|
||||
|
||||
```bash
|
||||
# Посмотреть свои группы в кластере
|
||||
kubectl auth whoami
|
||||
|
||||
# Попробовать создать привилегированный под (должен быть отклонён)
|
||||
kubectl apply -f - <<EOF
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: test-privileged
|
||||
namespace: default
|
||||
spec:
|
||||
containers:
|
||||
- name: app
|
||||
image: nginx:1.25.3
|
||||
securityContext:
|
||||
privileged: true
|
||||
resources:
|
||||
limits:
|
||||
memory: "128Mi"
|
||||
cpu: "100m"
|
||||
EOF
|
||||
# Ожидаем: error... не имеет права создавать привилегированные контейнеры
|
||||
```
|
||||
|
||||
## Cross-resource проверка через apiCall
|
||||
|
||||
```yaml
|
||||
# Читаем лейблы namespace во время обработки Pod запроса
|
||||
context:
|
||||
- name: nsLabels
|
||||
apiCall:
|
||||
urlPath: "/api/v1/namespaces/{{ request.object.metadata.namespace }}"
|
||||
jmesPath: "metadata.labels"
|
||||
|
||||
# Читаем список всех Deployments в namespace
|
||||
context:
|
||||
- name: existingDeployments
|
||||
apiCall:
|
||||
urlPath: "/apis/apps/v1/namespaces/{{ request.object.metadata.namespace }}/deployments"
|
||||
jmesPath: "items[].metadata.name"
|
||||
|
||||
# ВАЖНО: каждый apiCall = HTTP запрос к API Server.
|
||||
# Используйте с умом — это влияет на латентность admission.
|
||||
# Для часто используемых данных предпочитайте ConfigMap.
|
||||
```
|
||||
13
05-variables/02-context/deployment-freeze-config.yaml
Normal file
13
05-variables/02-context/deployment-freeze-config.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: deployment-freeze-config
|
||||
namespace: kyverno
|
||||
labels:
|
||||
app: kyverno-config
|
||||
data:
|
||||
# Установите freeze_active: "true" для блокировки деплойментов
|
||||
freeze_active: "false"
|
||||
freeze_start: "2024-12-24T00:00:00Z"
|
||||
freeze_end: "2025-01-02T09:00:00Z"
|
||||
freeze_reason: "Новогодний feature freeze. Экстренные деплои — через oncall."
|
||||
52
05-variables/02-context/restrict-deploys-during-freeze.yaml
Normal file
52
05-variables/02-context/restrict-deploys-during-freeze.yaml
Normal file
@@ -0,0 +1,52 @@
|
||||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: restrict-deploys-during-freeze
|
||||
annotations:
|
||||
policies.kyverno.io/title: "Блокировка деплойментов во время freeze"
|
||||
policies.kyverno.io/category: Governance
|
||||
policies.kyverno.io/severity: high
|
||||
policies.kyverno.io/subject: Deployment
|
||||
policies.kyverno.io/description: >-
|
||||
Блокирует создание новых Deployments когда в ConfigMap
|
||||
deployment-freeze-config поле freeze_active=true.
|
||||
Пользователи группы emergency-deployers и system:masters
|
||||
могут деплоить даже во время freeze.
|
||||
Активируйте freeze: kubectl patch configmap deployment-freeze-config
|
||||
-n kyverno --type merge -p '{"data":{"freeze_active":"true"}}'
|
||||
spec:
|
||||
rules:
|
||||
- name: check-freeze
|
||||
match:
|
||||
resources:
|
||||
kinds:
|
||||
- Deployment
|
||||
preconditions:
|
||||
any:
|
||||
- key: "{{ request.operation }}"
|
||||
operator: Equals
|
||||
value: CREATE
|
||||
context:
|
||||
- name: freezeConfig
|
||||
configMap:
|
||||
name: deployment-freeze-config
|
||||
namespace: kyverno
|
||||
validate:
|
||||
message: >-
|
||||
Деплойменты заморожены с {{ freezeConfig.data.freeze_start }}
|
||||
до {{ freezeConfig.data.freeze_end }}.
|
||||
Причина: {{ freezeConfig.data.freeze_reason }}
|
||||
Для экстренного деплоя обратитесь к oncall инженеру.
|
||||
deny:
|
||||
conditions:
|
||||
all:
|
||||
# Freeze активен
|
||||
- key: "{{ freezeConfig.data.freeze_active }}"
|
||||
operator: Equals
|
||||
value: "true"
|
||||
# Пользователь НЕ в группе экстренного деплоя
|
||||
- key: "{{ request.userInfo.groups }}"
|
||||
operator: AllNotIn
|
||||
value:
|
||||
- emergency-deployers
|
||||
- system:masters
|
||||
45
05-variables/02-context/restrict-privileged-non-admins.yaml
Normal file
45
05-variables/02-context/restrict-privileged-non-admins.yaml
Normal file
@@ -0,0 +1,45 @@
|
||||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: restrict-privileged-for-non-admins
|
||||
annotations:
|
||||
policies.kyverno.io/title: "Привилегированные контейнеры — только для администраторов"
|
||||
policies.kyverno.io/category: Security
|
||||
policies.kyverno.io/severity: high
|
||||
policies.kyverno.io/subject: Pod
|
||||
policies.kyverno.io/description: >-
|
||||
Запрещает создание привилегированных контейнеров для обычных пользователей.
|
||||
Администраторы (system:masters, cluster-admins) могут создавать
|
||||
привилегированные поды для системных нужд.
|
||||
Использует request.userInfo для проверки прав запрашивающего.
|
||||
spec:
|
||||
rules:
|
||||
- name: restrict-privileged-non-admin
|
||||
match:
|
||||
resources:
|
||||
kinds:
|
||||
- Pod
|
||||
# Precondition: применять только если пользователь НЕ администратор
|
||||
preconditions:
|
||||
all:
|
||||
- key: "system:masters"
|
||||
operator: NotIn
|
||||
value: "{{ request.userInfo.groups }}"
|
||||
- key: "cluster-admins"
|
||||
operator: NotIn
|
||||
value: "{{ request.userInfo.groups }}"
|
||||
validate:
|
||||
message: >-
|
||||
Пользователь '{{ request.userInfo.username }}' не имеет права
|
||||
создавать привилегированные контейнеры.
|
||||
Обратитесь к cluster-admin для выполнения системных задач.
|
||||
foreach:
|
||||
- list: >-
|
||||
request.object.spec.containers[] |
|
||||
merge(request.object.spec.initContainers[] || `[]`, @)
|
||||
deny:
|
||||
conditions:
|
||||
any:
|
||||
- key: "{{ element.securityContext.privileged }}"
|
||||
operator: Equals
|
||||
value: true
|
||||
128
05-variables/03-templates/README.md
Normal file
128
05-variables/03-templates/README.md
Normal file
@@ -0,0 +1,128 @@
|
||||
# Урок 5.3 — Переиспользуемые шаблоны политик (Helm Chart)
|
||||
|
||||
## Структура
|
||||
|
||||
```
|
||||
kyverno-policies/
|
||||
├── Chart.yaml
|
||||
├── values.yaml # дефолтные значения
|
||||
├── values-staging.yaml # overrides для staging
|
||||
├── values-production.yaml # overrides для production
|
||||
├── templates/
|
||||
│ ├── require-resource-limits.yaml
|
||||
│ ├── disallow-privileged.yaml
|
||||
│ ├── require-labels.yaml
|
||||
│ └── generate-networkpolicy.yaml
|
||||
└── tests/
|
||||
├── kyverno-test.yaml
|
||||
└── resources/
|
||||
├── pod-compliant.yaml
|
||||
├── pod-no-limits.yaml
|
||||
├── pod-privileged.yaml
|
||||
└── deployment-no-labels.yaml
|
||||
```
|
||||
|
||||
## Запуск тестов (без кластера)
|
||||
|
||||
```bash
|
||||
cd kyverno-policies
|
||||
|
||||
# Сгенерировать манифесты из шаблонов и протестировать
|
||||
helm template . -f values.yaml | \
|
||||
kyverno apply - --resource tests/resources/ --table
|
||||
|
||||
# Запустить встроенные kyverno тесты
|
||||
# (сначала нужно отрендерить шаблоны в обычные YAML)
|
||||
helm template . -f values.yaml --output-dir /tmp/rendered-policies
|
||||
|
||||
kyverno test tests/ \
|
||||
--policy-report \
|
||||
--detailed-results
|
||||
```
|
||||
|
||||
## Деплой в кластер
|
||||
|
||||
```bash
|
||||
# Staging — всё в Audit
|
||||
helm upgrade --install kyverno-policies . \
|
||||
--namespace kyverno \
|
||||
--create-namespace \
|
||||
-f values-staging.yaml
|
||||
|
||||
# Production — Enforce
|
||||
helm upgrade --install kyverno-policies . \
|
||||
--namespace kyverno \
|
||||
--create-namespace \
|
||||
-f values-production.yaml
|
||||
|
||||
# Проверить задеплоенные политики
|
||||
kubectl get clusterpolicies -l helm.sh/chart=kyverno-policies-1.0.0
|
||||
|
||||
# Rollback если что-то пошло не так
|
||||
helm rollback kyverno-policies 1 -n kyverno
|
||||
```
|
||||
|
||||
## PolicyException — управляемые исключения
|
||||
|
||||
```bash
|
||||
# Применить временное исключение для legacy-сервиса
|
||||
kubectl apply -f - <<EOF
|
||||
apiVersion: kyverno.io/v2beta1
|
||||
kind: PolicyException
|
||||
metadata:
|
||||
name: legacy-app-exception
|
||||
namespace: production
|
||||
annotations:
|
||||
exception.company.com/expires: "2025-03-01"
|
||||
exception.company.com/reason: "Migration in progress — JIRA-1234"
|
||||
exception.company.com/approved-by: "platform-team"
|
||||
spec:
|
||||
exceptions:
|
||||
- policyName: require-resource-limits
|
||||
ruleNames:
|
||||
- check-container-limits
|
||||
match:
|
||||
resources:
|
||||
kinds:
|
||||
- Pod
|
||||
namespaces:
|
||||
- production
|
||||
names:
|
||||
- legacy-app-*
|
||||
EOF
|
||||
|
||||
# Посмотреть все активные исключения
|
||||
kubectl get policyexceptions -A
|
||||
```
|
||||
|
||||
## CI/CD для Helm chart политик
|
||||
|
||||
```bash
|
||||
# Линтинг
|
||||
helm lint . -f values.yaml
|
||||
helm lint . -f values-production.yaml
|
||||
|
||||
# Dry-run деплой
|
||||
helm upgrade --install kyverno-policies . \
|
||||
--namespace kyverno \
|
||||
-f values-production.yaml \
|
||||
--dry-run
|
||||
|
||||
# diff перед применением (требует helm-diff plugin)
|
||||
helm plugin install https://github.com/databus23/helm-diff
|
||||
helm diff upgrade kyverno-policies . \
|
||||
--namespace kyverno \
|
||||
-f values-production.yaml
|
||||
```
|
||||
|
||||
## Версионирование изменений
|
||||
|
||||
```yaml
|
||||
# При изменении политики — обновляйте версию в Chart.yaml
|
||||
# и добавляйте запись в аннотацию политики:
|
||||
annotations:
|
||||
policies.kyverno.io/version: "1.1.0"
|
||||
policies.kyverno.io/changelog: |
|
||||
1.1.0: Добавлена проверка ephemeral containers
|
||||
1.0.0: Начальная версия
|
||||
```
|
||||
16
05-variables/03-templates/kyverno-policies/Chart.yaml
Normal file
16
05-variables/03-templates/kyverno-policies/Chart.yaml
Normal file
@@ -0,0 +1,16 @@
|
||||
apiVersion: v2
|
||||
name: kyverno-policies
|
||||
description: >-
|
||||
Корпоративные политики безопасности Kyverno.
|
||||
Содержит базовый набор validation, mutation и generation политик.
|
||||
type: application
|
||||
version: 1.0.0
|
||||
appVersion: "1.11"
|
||||
keywords:
|
||||
- kyverno
|
||||
- policy
|
||||
- security
|
||||
- kubernetes
|
||||
maintainers:
|
||||
- name: Platform Team
|
||||
email: platform@company.com
|
||||
@@ -0,0 +1,42 @@
|
||||
{{- if .Values.disallowPrivileged.enabled }}
|
||||
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/version: {{ .Chart.Version }}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
|
||||
spec:
|
||||
validationFailureAction: {{ .Values.disallowPrivileged.failureAction | default .Values.global.failureAction }}
|
||||
background: true
|
||||
rules:
|
||||
- name: privileged-containers
|
||||
match:
|
||||
resources:
|
||||
kinds:
|
||||
- Pod
|
||||
exclude:
|
||||
resources:
|
||||
namespaces:
|
||||
{{- range .Values.global.excludedNamespaces }}
|
||||
- {{ . }}
|
||||
{{- end }}
|
||||
validate:
|
||||
message: >-
|
||||
Контейнер '{{ "{{" }} element.name {{ "}}" }}' имеет privileged: true.
|
||||
Привилегированные контейнеры запрещены политикой безопасности.
|
||||
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
|
||||
{{- end }}
|
||||
@@ -0,0 +1,44 @@
|
||||
{{- if .Values.generateNetworkPolicy.enabled }}
|
||||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: generate-default-networkpolicy
|
||||
annotations:
|
||||
policies.kyverno.io/title: "Генерация NetworkPolicy по умолчанию"
|
||||
policies.kyverno.io/category: Security
|
||||
policies.kyverno.io/severity: high
|
||||
policies.kyverno.io/version: {{ .Chart.Version }}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
|
||||
spec:
|
||||
rules:
|
||||
- name: generate-deny-all
|
||||
match:
|
||||
resources:
|
||||
kinds:
|
||||
- Namespace
|
||||
exclude:
|
||||
resources:
|
||||
names:
|
||||
{{- range (concat .Values.global.excludedNamespaces .Values.generateNetworkPolicy.excludedNamespaces) | uniq }}
|
||||
- {{ . }}
|
||||
{{- end }}
|
||||
generate:
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
name: default-deny-all
|
||||
namespace: "{{ "{{" }} request.object.metadata.name {{ "}}" }}"
|
||||
synchronize: true
|
||||
data:
|
||||
kind: NetworkPolicy
|
||||
apiVersion: networking.k8s.io/v1
|
||||
metadata:
|
||||
name: default-deny-all
|
||||
labels:
|
||||
generated-by: kyverno
|
||||
helm-release: {{ .Release.Name }}
|
||||
spec:
|
||||
podSelector: {}
|
||||
policyTypes:
|
||||
- Ingress
|
||||
- Egress
|
||||
{{- end }}
|
||||
@@ -0,0 +1,40 @@
|
||||
{{- if .Values.requiredLabels.enabled }}
|
||||
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/version: {{ .Chart.Version }}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
|
||||
spec:
|
||||
validationFailureAction: {{ .Values.requiredLabels.failureAction | default .Values.global.failureAction }}
|
||||
background: true
|
||||
rules:
|
||||
- name: check-required-labels
|
||||
match:
|
||||
resources:
|
||||
kinds:
|
||||
- Deployment
|
||||
- StatefulSet
|
||||
- DaemonSet
|
||||
exclude:
|
||||
resources:
|
||||
namespaces:
|
||||
{{- range .Values.global.excludedNamespaces }}
|
||||
- {{ . }}
|
||||
{{- end }}
|
||||
validate:
|
||||
message: >-
|
||||
Ресурс '{{ "{{" }} request.object.metadata.name {{ "}}" }}'
|
||||
должен иметь все обязательные лейблы:
|
||||
{{ .Values.requiredLabels.labels | join ", " }}
|
||||
pattern:
|
||||
metadata:
|
||||
labels:
|
||||
{{- range .Values.requiredLabels.labels }}
|
||||
{{ . }}: "?*"
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,41 @@
|
||||
{{- if .Values.resourceLimits.enabled }}
|
||||
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/version: {{ .Chart.Version }}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
|
||||
spec:
|
||||
validationFailureAction: {{ .Values.resourceLimits.failureAction | default .Values.global.failureAction }}
|
||||
background: true
|
||||
rules:
|
||||
- name: check-container-limits
|
||||
match:
|
||||
resources:
|
||||
kinds:
|
||||
- Pod
|
||||
exclude:
|
||||
resources:
|
||||
namespaces:
|
||||
{{- range .Values.global.excludedNamespaces }}
|
||||
- {{ . }}
|
||||
{{- end }}
|
||||
validate:
|
||||
message: >-
|
||||
Контейнер '{{ "{{" }} element.name {{ "}}" }}' не имеет resource limits.
|
||||
Добавьте resources.limits.memory и resources.limits.cpu.
|
||||
foreach:
|
||||
- list: >-
|
||||
request.object.spec.containers[] |
|
||||
merge(request.object.spec.initContainers[] || `[]`, @) |
|
||||
merge(request.object.spec.ephemeralContainers[] || `[]`, @)
|
||||
pattern:
|
||||
resources:
|
||||
limits:
|
||||
memory: "?*"
|
||||
cpu: "?*"
|
||||
{{- end }}
|
||||
@@ -0,0 +1,31 @@
|
||||
name: kyverno-policies-chart-tests
|
||||
policies:
|
||||
- ../templates/require-resource-limits.yaml
|
||||
- ../templates/disallow-privileged.yaml
|
||||
- ../templates/require-labels.yaml
|
||||
resources:
|
||||
- resources/pod-compliant.yaml
|
||||
- resources/pod-no-limits.yaml
|
||||
- resources/pod-privileged.yaml
|
||||
- resources/deployment-no-labels.yaml
|
||||
results:
|
||||
- policy: require-resource-limits
|
||||
rule: check-container-limits
|
||||
resource: pod-compliant
|
||||
namespace: default
|
||||
result: pass
|
||||
- policy: require-resource-limits
|
||||
rule: check-container-limits
|
||||
resource: pod-no-limits
|
||||
namespace: default
|
||||
result: fail
|
||||
- policy: disallow-privileged-containers
|
||||
rule: privileged-containers
|
||||
resource: pod-privileged
|
||||
namespace: default
|
||||
result: fail
|
||||
- policy: require-standard-labels
|
||||
rule: check-required-labels
|
||||
resource: deployment-no-labels
|
||||
namespace: default
|
||||
result: fail
|
||||
@@ -0,0 +1,23 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: deployment-no-labels
|
||||
namespace: default
|
||||
# нет лейблов app, team, environment
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
run: app
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
run: app
|
||||
spec:
|
||||
containers:
|
||||
- name: app
|
||||
image: nginx:1.25.3
|
||||
resources:
|
||||
limits:
|
||||
memory: "128Mi"
|
||||
cpu: "100m"
|
||||
@@ -0,0 +1,16 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: pod-compliant
|
||||
namespace: default
|
||||
spec:
|
||||
containers:
|
||||
- name: app
|
||||
image: nginx:1.25.3
|
||||
resources:
|
||||
requests:
|
||||
memory: "64Mi"
|
||||
cpu: "50m"
|
||||
limits:
|
||||
memory: "128Mi"
|
||||
cpu: "100m"
|
||||
@@ -0,0 +1,9 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: pod-no-limits
|
||||
namespace: default
|
||||
spec:
|
||||
containers:
|
||||
- name: app
|
||||
image: nginx:1.25.3
|
||||
@@ -0,0 +1,15 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: pod-privileged
|
||||
namespace: default
|
||||
spec:
|
||||
containers:
|
||||
- name: app
|
||||
image: nginx:1.25.3
|
||||
securityContext:
|
||||
privileged: true
|
||||
resources:
|
||||
limits:
|
||||
memory: "128Mi"
|
||||
cpu: "100m"
|
||||
@@ -0,0 +1,21 @@
|
||||
# Production overrides
|
||||
global:
|
||||
failureAction: Enforce
|
||||
|
||||
resourceLimits:
|
||||
enabled: true
|
||||
maxMemory: "8Gi"
|
||||
maxCpu: "8"
|
||||
|
||||
disallowLatestTag:
|
||||
enabled: true
|
||||
failureAction: Enforce
|
||||
|
||||
requiredLabels:
|
||||
enabled: true
|
||||
failureAction: Enforce
|
||||
labels:
|
||||
- app
|
||||
- team
|
||||
- environment
|
||||
- version
|
||||
@@ -0,0 +1,10 @@
|
||||
# Staging overrides — всё в Audit для наблюдения
|
||||
global:
|
||||
failureAction: Audit
|
||||
|
||||
disallowPrivileged:
|
||||
enabled: true
|
||||
failureAction: Audit # в staging даже security в Audit
|
||||
|
||||
generateNetworkPolicy:
|
||||
enabled: false # в staging не генерируем NetworkPolicy
|
||||
55
05-variables/03-templates/kyverno-policies/values.yaml
Normal file
55
05-variables/03-templates/kyverno-policies/values.yaml
Normal file
@@ -0,0 +1,55 @@
|
||||
# Дефолтные значения для kyverno-policies Helm chart.
|
||||
# Переопределите в values-staging.yaml или values-production.yaml.
|
||||
|
||||
global:
|
||||
# Audit = фиксировать нарушения, Enforce = блокировать
|
||||
failureAction: Audit
|
||||
excludedNamespaces:
|
||||
- kube-system
|
||||
- kube-public
|
||||
- kube-node-lease
|
||||
- kyverno
|
||||
|
||||
# --- Политика: resource limits ---
|
||||
resourceLimits:
|
||||
enabled: true
|
||||
failureAction: "" # пусто = использовать global.failureAction
|
||||
maxMemory: "4Gi"
|
||||
maxCpu: "4"
|
||||
|
||||
# --- Политика: запрет latest тега ---
|
||||
disallowLatestTag:
|
||||
enabled: true
|
||||
failureAction: ""
|
||||
|
||||
# --- Политика: обязательные лейблы ---
|
||||
requiredLabels:
|
||||
enabled: true
|
||||
failureAction: ""
|
||||
labels:
|
||||
- app
|
||||
- team
|
||||
- environment
|
||||
|
||||
# --- Политика: привилегированные контейнеры ---
|
||||
disallowPrivileged:
|
||||
enabled: true
|
||||
# security политики всегда Enforce
|
||||
failureAction: Enforce
|
||||
|
||||
# --- Политика: запрет host namespaces ---
|
||||
disallowHostNamespaces:
|
||||
enabled: true
|
||||
failureAction: Enforce
|
||||
|
||||
# --- Политика: автодобавление лейблов (mutation) ---
|
||||
addStandardLabels:
|
||||
enabled: true
|
||||
|
||||
# --- Политика: генерация NetworkPolicy ---
|
||||
generateNetworkPolicy:
|
||||
enabled: true
|
||||
excludedNamespaces:
|
||||
- monitoring
|
||||
- logging
|
||||
- istio-system
|
||||
Reference in New Issue
Block a user