From 9342806c3fb909f848f3da3d426a9f144ef4aabc Mon Sep 17 00:00:00 2001 From: Vassiliy Yegorov Date: Sat, 18 Apr 2026 10:43:01 +0700 Subject: [PATCH] init --- .../set-resource-limits-from-config.yaml | 8 +++ 05-variables/02-context/another-examples.yaml | 57 +++++++++++++++++++ .../restrict-deploys-during-freeze.yaml | 2 +- .../02-context/validate-on-create-only.yaml | 33 +++++++++++ .../.github/workflows/policy-ci.yaml | 43 ++++++++++++++ 5 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 05-variables/02-context/another-examples.yaml create mode 100644 05-variables/02-context/validate-on-create-only.yaml create mode 100644 05-variables/03-templates/github-actions/.github/workflows/policy-ci.yaml diff --git a/05-variables/01-configmaps/set-resource-limits-from-config.yaml b/05-variables/01-configmaps/set-resource-limits-from-config.yaml index a4fac02..850f79a 100644 --- a/05-variables/01-configmaps/set-resource-limits-from-config.yaml +++ b/05-variables/01-configmaps/set-resource-limits-from-config.yaml @@ -28,6 +28,14 @@ spec: configMap: name: kyverno-global-config namespace: kyverno + # - name: globalConfig + # apiCall: + # urlPath: "/api/v1/namespaces/kyverno/configmaps/kyverno-global-config" + # jmesPath: "data" + # - name: apiCredentials + # apiCall: + # urlPath: "/api/v1/namespaces/kyverno/secrets/policy-api-credentials" + # jmesPath: "data.api-key | base64_decode(@)" mutate: foreach: - list: "request.object.spec.containers" diff --git a/05-variables/02-context/another-examples.yaml b/05-variables/02-context/another-examples.yaml new file mode 100644 index 0000000..f2ee1db --- /dev/null +++ b/05-variables/02-context/another-examples.yaml @@ -0,0 +1,57 @@ +# Другие варианты проверок +# +# проверить, что PVC использует StorageClass из одобренного списка: +# +rules: +- name: check-storage-class + match: + resources: + kinds: + - PersistentVolumeClaim + context: + - name: storageClassInfo + apiCall: + urlPath: "/apis/storage.k8s.io/v1/storageclasses/{{ request.object.spec.storageClassName }}" + jmesPath: "metadata.labels.\"approved-for-production\"" + validate: + message: >- + StorageClass '{{ request.object.spec.storageClassName }}' не одобрена для production. + Используйте StorageClass с лейблом approved-for-production: "true" + deny: + conditions: + - key: "{{ storageClassInfo }}" + operator: NotEquals + value: "true" + +# проверить, что количество реплик не превышает кворум с учётом текущей нагрузки: +# +context: +- name: existingDeployments + apiCall: + urlPath: >- + /apis/apps/v1/namespaces/{{ request.object.metadata.namespace }}/deployments + jmesPath: "items[?metadata.name != '{{ request.object.metadata.name }}'] | length(@)" +validate: + message: >- + В namespace уже {{ existingDeployments }} деплойментов. + Максимум разрешено 20. + deny: + conditions: + - key: "{{ existingDeployments }}" + operator: GreaterThanOrEquals + value: "20" + +# принимать решения на основе состояния нод +# +context: +- name: nodesInfo + apiCall: + urlPath: "/api/v1/nodes" + jmesPath: "items[?metadata.labels.\"node-type\" == 'gpu'].metadata.name" +validate: + message: "GPU workloads требуют минимум 2 GPU-ноды в кластере" + deny: + conditions: + - key: "{{ length(nodesInfo) }}" + operator: LessThan + value: "2" \ No newline at end of file diff --git a/05-variables/02-context/restrict-deploys-during-freeze.yaml b/05-variables/02-context/restrict-deploys-during-freeze.yaml index f5ffbdb..2fc7358 100644 --- a/05-variables/02-context/restrict-deploys-during-freeze.yaml +++ b/05-variables/02-context/restrict-deploys-during-freeze.yaml @@ -49,4 +49,4 @@ spec: operator: AllNotIn value: - emergency-deployers - - system:masters + - system:masters \ No newline at end of file diff --git a/05-variables/02-context/validate-on-create-only.yaml b/05-variables/02-context/validate-on-create-only.yaml new file mode 100644 index 0000000..9536830 --- /dev/null +++ b/05-variables/02-context/validate-on-create-only.yaml @@ -0,0 +1,33 @@ +# Полезный паттерн — разные правила для CREATE и UPDATE + +rules: +- name: validate-on-create-only + match: + resources: + kinds: + - Deployment + preconditions: + any: + - key: "{{ request.operation }}" + operator: Equals + value: CREATE + validate: + # применяется только при создании + +- name: validate-image-on-update + match: + resources: + kinds: + - Deployment + preconditions: + all: + - key: "{{ request.operation }}" + operator: Equals + value: UPDATE + - key: >- + {{ request.object.spec.template.spec.containers[0].image }} + operator: NotEquals + value: >- + {{ request.oldObject.spec.template.spec.containers[0].image }} + validate: + # применяется только при UPDATE с изменением образа \ No newline at end of file diff --git a/05-variables/03-templates/github-actions/.github/workflows/policy-ci.yaml b/05-variables/03-templates/github-actions/.github/workflows/policy-ci.yaml new file mode 100644 index 0000000..2670af7 --- /dev/null +++ b/05-variables/03-templates/github-actions/.github/workflows/policy-ci.yaml @@ -0,0 +1,43 @@ +# .github/workflows/policy-ci.yaml +name: Kyverno Policy CI + +on: + pull_request: + paths: + - 'policies/**' + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install Kyverno CLI + run: | + curl -LO https://github.com/kyverno/kyverno/releases/latest/download/kyverno-cli_linux_amd64.tar.gz + tar -xzf kyverno-cli_linux_amd64.tar.gz + sudo mv kyverno /usr/local/bin/ + + - name: Lint policies + run: | + kyverno apply policies/ --resource test-resources/ --detailed-results + + - name: Run tests + run: | + kyverno test policies/tests/ + + - name: Validate helm chart + run: | + helm lint kyverno-policies/ + helm template kyverno-policies/ | kyverno apply - --resource test-resources/ + + deploy-staging: + needs: test + if: github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + steps: + - name: Deploy to staging + run: | + helm upgrade --install kyverno-policies ./kyverno-policies \ + -f values-staging.yaml \ + --kubeconfig ${{ secrets.STAGING_KUBECONFIG }} \ No newline at end of file