Урок 7.2 — Работа с внешними данными и API
Файлы
| Файл | Описание |
|---|---|
check-image-vulnerabilities.yaml |
Проверка уязвимостей через внешний API |
external-data-cache.yaml |
ConfigMap + CronJob + RBAC для кэша внешних данных |
validate-registry-from-cache.yaml |
Валидация реестра через кэшированный ConfigMap |
Паттерн 1: Прямой вызов внешнего API
# Требует включения в Kyverno:
# admissionController.extraArgs:
# - --enableExternalDataCall=true
context:
- name: result
apiCall:
urlPath: "https://your-api.company.com/check"
method: POST
data:
- key: image
value: "{{ request.object.spec.containers[0].image }}"
jmesPath: "status"
Включение external data calls
helm upgrade kyverno kyverno/kyverno \
--namespace kyverno \
--reuse-values \
--set admissionController.extraArgs="{--enableExternalDataCall=true}"
# Проверить
kubectl get deployment kyverno-admission-controller -n kyverno \
-o jsonpath='{.spec.template.spec.containers[0].args}' | \
grep enableExternalDataCall
Паттерн 2: Кэш через ConfigMap (рекомендуется)
Прямые вызовы внешних API медленные и создают зависимость. Лучший паттерн: CronJob обновляет ConfigMap → политика читает из ConfigMap.
Внешний API ──(каждые N минут)──► CronJob ──► ConfigMap
│
Kyverno политика ◄───┘
(кэш, быстро)
Применение кэша
# Применить всё: ConfigMap + CronJob + RBAC
kubectl apply -f external-data-cache.yaml
# Проверить ConfigMap
kubectl get configmap external-data-cache -n kyverno -o yaml
# Запустить CronJob вручную для немедленного обновления
kubectl create job --from=cronjob/update-policy-cache \
manual-update -n kyverno
# Следить за логами
kubectl logs -n kyverno \
-l job-name=manual-update \
--follow
# Применить политику использующую кэш
kubectl apply -f validate-registry-from-cache.yaml
Паттерн 3: HashiCorp Vault интеграция
# Проверить доступность Vault перед деплоем с Vault секретами
kubectl apply -f - <<EOF
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: check-vault-availability
spec:
rules:
- name: verify-vault-health
match:
resources:
kinds: [Pod]
preconditions:
any:
- key: "{{ request.object.metadata.annotations.\"vault.hashicorp.com/agent-inject\" }}"
operator: Equals
value: "true"
context:
- name: vaultHealth
apiCall:
urlPath: "https://vault.company.com:8200/v1/sys/health"
jmesPath: "initialized"
validate:
message: "Vault недоступен. Деплой с Vault секретами временно заблокирован."
deny:
conditions:
- key: "{{ vaultHealth }}"
operator: NotEquals
value: true
EOF
Обработка недоступности внешнего API
# Fail-open vs Fail-closed
# Выбор зависит от критичности проверки
# Fail-open (разрешить если API недоступен):
# jmesPath: "result || 'ALLOWED'"
# deny если result == "DENIED"
# При недоступности: result = "ALLOWED" → под создаётся
# Fail-closed (запретить если API недоступен):
# jmesPath: "result || 'DENIED'"
# deny если result != "ALLOWED"
# При недоступности: result = "DENIED" → под НЕ создаётся
Настройка timeout для внешних вызовов
# Webhook timeout влияет на все вызовы включая внешние API
helm upgrade kyverno kyverno/kyverno \
--namespace kyverno \
--reuse-values \
--set config.webhooks.timeoutSeconds=15
# По умолчанию 10 секунд. Увеличьте если внешний API медленный.
# Максимум — 30 секунд (ограничение Kubernetes).
Мониторинг внешних вызовов
# Проверить что CronJob работает регулярно
kubectl get cronjobs -n kyverno
kubectl get jobs -n kyverno | grep update-policy-cache
# Последнее обновление кэша
kubectl get configmap external-data-cache -n kyverno \
-o jsonpath='{.data.last-updated}'
# Алерт если кэш устарел (добавьте в PrometheusRule)
# Используйте kube_configmap_info метрику и проверяйте
# что last-updated не старше N минут
Безопасность при работе с внешними данными
# НЕ хардкодьте токены в политиках — используйте Secret
kubectl create secret generic external-api-token \
--from-literal=token=your-secret-token \
-n kyverno
# В политике читаем из Secret
# context:
# - name: apiToken
# apiCall:
# urlPath: "/api/v1/namespaces/kyverno/secrets/external-api-token"
# jmesPath: "data.token | base64_decode(@)"