Разработка кастомных Admission Webhooks для Kubernetes
Наша команда часто сталкивается с ситуацией: инженеры деплоят Pod без resources.requests, с securityContext и imagePullPolicy: Never, используя latest-тег. Политики Kyverno или OPA Gatekeeper могут запретить это на уровне правил. Но если логика требует обращения к внешнему сервису — корпоративному API для проверки секретов или автоматической простановки аннотаций на основе бизнес-правил? В таких случаях стандартные инструменты бессильны. Мы разрабатываем кастомные Admission Webhooks — гибкое решение для валидации и мутации любых ресурсов Kubernetes. Свяжитесь с нами, чтобы обсудить ваш кейс — мы поможем автоматизировать политики и сэкономить бюджет на поддержку кластера.
Два типа вебхуков: Validating и Mutating
ValidatingAdmissionWebhook получает объект, возвращает разрешить или отклонить, не изменяя его. Используется для проверок: "этот ImagePullSecret существует?", "у namespace есть approved label?", "образ не содержит уязвимостей?" через сторонний сканер. MutatingAdmissionWebhook может изменять объект с помощью JSON Patch перед сохранением. Применяется для автоподстановки sidecar-контейнеров, добавления аннотаций, нормализации полей, инжекции переменных окружения.
| Характеристика | Validating Webhook | Mutating Webhook |
|---|---|---|
| Изменяет объект? | Нет | Да (JSON Patch) |
| Порядок вызова | После всех мутаций | Первыми, параллельно |
| Типичное применение | Валидация параметров безопасности | Добавление sidecar, аннотаций |
Порядок вызова: сначала все Mutating вебхуки (параллельно, затем при изменениях повторно), затем все Validating (параллельно). Validating вебхук видит финальный объект после всех мутаций.
Почему кастомный webhook, а не Kyverno?
Kyverno — отличный инструмент для статических политик на основе Rego. Но когда требуется обращение к внешнему API (например, проверка лицензии контейнера), сложная бизнес-логика с ветвлениями и циклами, интеграция с системой тикетов (Jira) или CMDB, динамическая генерация конфигурации на основе метаданных кластера — тогда кастомный webhook на Go или Python даёт полный контроль. Он работает в 2–3 раза быстрее при большом количестве обращений, так как не тратит время на интерпретацию Rego-правил. Стоимость разработки окупается за счёт предотвращения сбоев и сокращения времени на ручные проверки.
Как обеспечить отказоустойчивость вебхука?
Admission Webhook должен быть развёрнут минимум с двумя репликами (HPA) и настроен с failurePolicy: Fail для критических проверок. Используйте namespaceSelector, чтобы исключить системные namespace (kube-system). Сертификаты TLS обновляются автоматически через cert-manager. Таймаут вебхука — не более 5 секунд, иначе замедлится работа кластера. Экономия на инцидентах может составить до 30% времени простоя.
Структура вебхука: что внутри
Вебхук — это HTTPS-сервер, принимающий AdmissionReview запросы. Пример на Go:
package main
import (
"encoding/json"
"net/http"
admissionv1 "k8s.io/api/admission/v1"
corev1 "k8s.io/api/core/v1"
)
func validatePod(w http.ResponseWriter, r *http.Request) {
var admReview admissionv1.AdmissionReview
json.NewDecoder(r.Body).Decode(&admReview)
pod := &corev1.Pod{}
json.Unmarshal(admReview.Request.Object.Raw, pod)
allowed := true
message := ""
for _, container := range pod.Spec.Containers {
if container.Resources.Requests == nil {
allowed = false
message = "container " + container.Name + " must specify resources.requests"
break
}
}
response := admissionv1.AdmissionReview{
TypeMeta: admReview.TypeMeta,
Response: &admissionv1.AdmissionResponse{
UID: admReview.Request.UID,
Allowed: allowed,
Result: &metav1.Status{
Message: message,
},
},
}
json.NewEncoder(w).Encode(response)
}Вебхук должен работать по HTTPS с TLS-сертификатом, подписанным кластерным или доверенным CA. Kubernetes не принимает HTTP и не принимает самоподписанные сертификаты без явного caBundle в WebhookConfiguration.
Регистрация вебхука
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: pod-validator
webhooks:
- name: validate.pods.example.com
admissionReviewVersions: ["v1"]
clientConfig:
service:
name: pod-validator
namespace: webhook-system
path: /validate
caBundle: <BASE64_CA_CERT>
rules:
- operations: ["CREATE", "UPDATE"]
apiGroups: [""]
apiVersions: ["v1"]
resources: ["pods"]
failurePolicy: Fail # Ignore или Fail
namespaceSelector:
matchExpressions:
- key: webhook-validation
operator: In
values: ["enabled"]
sideEffects: None
timeoutSeconds: 5 | Параметр | Fail | Ignore |
|---|---|---|
| Если вебхук недоступен | Блокирует создание ресурса | Пропускает проверку |
| Для каких политик | Критические политики безопасности | Вспомогательные аннотации |
| Влияние на кластер | Останавливает деплой при сбое вебхука | Позволяет игнорировать ошибки вебхука |
timeoutSeconds: 5 — Kubernetes ждёт ответа вебхука максимум 5 секунд. Медленный вебхук замедляет создание всех Pod в кластере. Это главная причина, почему вебхук должен быть быстрым: никаких синхронных обращений к медленным внешним API.
namespaceSelector — вебхук применяется только к namespace с лейблом webhook-validation=enabled. Обязательно исключите kube-system и webhook-system, иначе вебхук может заблокировать системные компоненты.
Mutating вебхук: JSON Patch
Возврат патча для автодобавления labels и переменных окружения:
patch := []map[string]interface{}{
{
"op": "add",
"path": "/metadata/labels/injected-by",
"value": "admission-webhook",
},
{
"op": "add",
"path": "/spec/containers/0/env/-",
"value": map[string]string{
"name": "TENANT_ID",
"value": tenantID,
},
},
}
patchBytes, _ := json.Marshal(patch)
patchType := admissionv1.PatchTypeJSONPatch
response.Patch = patchBytes
response.PatchType = &patchType
TLS и деплой
Для управления TLS-сертификатами используем cert-manager. Ресурс Certificate с issuerRef на кластерный CA автоматически создаёт Secret с сертификатом и обновляет его при истечении. Webhook caBundle обновляется через аннотацию:
metadata: annotations: cert-manager.io/inject-ca-from: webhook-system/pod-validator-cert Это избавляет от ручной ротации сертификата — одной из самых частых причин инцидентов, когда webhook cert expires и все деплои начинают падать.
Что входит в работу
- Разработка сервера на Go (или Python) с бизнес-логикой
- Unit-тесты и интеграционные тесты (envtest, kind)
- Настройка TLS через cert-manager
- Helm-чарт для деплоя в кластер
- CI/CD пайплайн (GitLab CI) с авторазвёртыванием
- Документация по настройке и эксплуатации
- Пост-релизная поддержка в течение 2 недель
- Обучение команды по администрированию
Этапы работы
- Аналитика — аудит текущих политик, описание требований (что валидировать/мутировать, какие ресурсы, namespace)
- Проектирование — архитектура webhook, схема данных, сценарии отказов
- Разработка — написание сервера, интеграционных тестов
- Тестирование — проверка на тестовом кластере (kind), нагрузочное тестирование
- Деплой — развёртывание в production с HPA и мониторингом
- Документация — инструкции для команды по изменению правил
Сроки и стоимость
Срок разработки — от 3 до 5 дней в зависимости от сложности логики. Стоимость рассчитывается индивидуально после аудита инфраструктуры. Свяжитесь с нами для оценки вашего проекта — мы имеем 5+ лет опыта с Kubernetes, реализовали более 30 подобных решений. Оставьте заявку, и мы подготовим предложение. Закажите консультацию, чтобы узнать, как кастомный вебхук может сэкономить ваш бюджет.
Официальная документация Kubernetes описывает Admission Webhooks как основной механизм расширения политик кластера (см. Kubernetes Admission Webhooks).







