fix pols for 1.18
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(kyverno version *)",
|
||||
"Bash(rtk curl *)",
|
||||
"Bash(tar -xzf /tmp/kyverno.tar.gz -C /tmp kyverno)",
|
||||
"Bash(sudo mv /tmp/kyverno /usr/local/bin/kyverno)",
|
||||
"Bash(mv /tmp/kyverno ~/bin/kyverno)",
|
||||
"Bash(mv /tmp/kyverno ~/.local/bin/kyverno)",
|
||||
"Bash(export PATH=\"$HOME/bin:$HOME/.local/bin:$PATH\")"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -26,22 +26,14 @@ spec:
|
||||
- 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[] || `[]`, @)
|
||||
message: >-
|
||||
Контейнер '{{ element.name }}' в поде '{{ request.object.metadata.name }}'
|
||||
не имеет resource limits. Добавьте resources.limits.memory и resources.limits.cpu.
|
||||
pattern:
|
||||
resources:
|
||||
limits:
|
||||
|
||||
@@ -25,20 +25,20 @@ spec:
|
||||
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[] || `[]`, @)
|
||||
merge(request.object.spec.initContainers[] || `[]`, @) |
|
||||
merge(request.object.spec.ephemeralContainers[] || `[]`, @)
|
||||
message: >-
|
||||
Образ '{{ element.image }}' использует тег :latest или не имеет тега.
|
||||
Используйте конкретный тег (nginx:1.25.3) или digest (nginx@sha256:...).
|
||||
deny:
|
||||
conditions:
|
||||
any:
|
||||
- key: "{{ element.image }}"
|
||||
operator: Contains
|
||||
value: ":latest"
|
||||
- key: "{{ element.image }}"
|
||||
operator: NotContains
|
||||
value: ":"
|
||||
- key: "{{ regex_match(':latest', element.image) }}"
|
||||
operator: Equals
|
||||
value: true
|
||||
- key: "{{ regex_match('^(([^/]+/)*[^/:]+)$', element.image) }}"
|
||||
operator: Equals
|
||||
value: true
|
||||
|
||||
@@ -27,25 +27,23 @@ spec:
|
||||
- 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[] || `[]`, @)
|
||||
merge(request.object.spec.initContainers[] || `[]`, @) |
|
||||
merge(request.object.spec.ephemeralContainers[] || `[]`, @)
|
||||
message: >-
|
||||
Образ '{{ element.image }}' из недоверенного реестра.
|
||||
Разрешены: registry.company.com/, gcr.io/company-project/.
|
||||
Загрузите образ в внутренний реестр и обновите манифест.
|
||||
deny:
|
||||
conditions:
|
||||
all:
|
||||
# Образ НЕ из первого доверенного реестра
|
||||
- key: "{{ element.image }}"
|
||||
operator: NotStartsWith
|
||||
value: "registry.company.com/"
|
||||
# И НЕ из второго доверенного реестра
|
||||
- key: "{{ element.image }}"
|
||||
operator: NotStartsWith
|
||||
value: "gcr.io/company-project/"
|
||||
# regex_match: false = образ НЕ начинается с доверенного реестра
|
||||
- key: "{{ regex_match('^registry\\.company\\.com/', element.image) }}"
|
||||
operator: Equals
|
||||
value: false
|
||||
- key: "{{ regex_match('^gcr\\.io/company-project/', element.image) }}"
|
||||
operator: Equals
|
||||
value: false
|
||||
# Добавьте дополнительные условия по аналогии
|
||||
|
||||
@@ -26,15 +26,14 @@ spec:
|
||||
namespaces:
|
||||
- kube-system
|
||||
validate:
|
||||
message: >-
|
||||
Контейнер '{{ element.name }}' добавляет запрещённые capabilities:
|
||||
{{ element.securityContext.capabilities.add }}.
|
||||
Разрешена только NET_BIND_SERVICE.
|
||||
Пересмотрите необходимость этих привилегий.
|
||||
foreach:
|
||||
- list: >-
|
||||
request.object.spec.containers[] |
|
||||
merge(request.object.spec.initContainers[] || `[]`, @)
|
||||
merge(request.object.spec.initContainers[] || `[]`, @) |
|
||||
merge(request.object.spec.ephemeralContainers[] || `[]`, @)
|
||||
message: >-
|
||||
Контейнер '{{ element.name }}' добавляет запрещённые capabilities.
|
||||
Разрешена только NET_BIND_SERVICE. Пересмотрите необходимость привилегий.
|
||||
deny:
|
||||
conditions:
|
||||
any:
|
||||
|
||||
@@ -52,6 +52,6 @@ spec:
|
||||
deny:
|
||||
conditions:
|
||||
any:
|
||||
- key: "{{ request.object.spec.volumes[].hostPath | length(@) }}"
|
||||
- key: "{{ request.object.spec.volumes[?hostPath] | length(@) }}"
|
||||
operator: GreaterThan
|
||||
value: "0"
|
||||
|
||||
@@ -26,15 +26,14 @@ spec:
|
||||
namespaces:
|
||||
- kube-system
|
||||
validate:
|
||||
message: >-
|
||||
Контейнер '{{ element.name }}' имеет securityContext.privileged: true.
|
||||
Привилегированные контейнеры запрещены — они получают полный доступ к хосту.
|
||||
Удалите поле securityContext.privileged или установите значение false.
|
||||
foreach:
|
||||
- list: >-
|
||||
request.object.spec.containers[] |
|
||||
merge(request.object.spec.initContainers[] || `[]`, @) |
|
||||
merge(request.object.spec.ephemeralContainers[] || `[]`, @)
|
||||
message: >-
|
||||
Контейнер '{{ element.name }}' имеет securityContext.privileged: true.
|
||||
Привилегированные контейнеры запрещены. Удалите поле или установите false.
|
||||
deny:
|
||||
conditions:
|
||||
any:
|
||||
|
||||
@@ -25,14 +25,14 @@ spec:
|
||||
namespaces:
|
||||
- kube-system
|
||||
validate:
|
||||
message: >-
|
||||
Контейнер '{{ element.name }}' не сбрасывает все capabilities.
|
||||
Добавьте в securityContext:
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
foreach:
|
||||
- list: "request.object.spec.containers"
|
||||
- list: >-
|
||||
request.object.spec.containers[] |
|
||||
merge(request.object.spec.initContainers[] || `[]`, @) |
|
||||
merge(request.object.spec.ephemeralContainers[] || `[]`, @)
|
||||
message: >-
|
||||
Контейнер '{{ element.name }}' не сбрасывает все capabilities.
|
||||
Добавьте securityContext.capabilities.drop: [ALL].
|
||||
deny:
|
||||
conditions:
|
||||
all:
|
||||
|
||||
@@ -45,11 +45,11 @@ spec:
|
||||
namespaces:
|
||||
- kube-system
|
||||
validate:
|
||||
message: >-
|
||||
Контейнер '{{ element.name }}' использует runAsUser: 0 (root).
|
||||
Установите runAsUser >= 1000.
|
||||
foreach:
|
||||
- list: "request.object.spec.containers"
|
||||
- list: >-
|
||||
request.object.spec.containers[] |
|
||||
merge(request.object.spec.initContainers[] || `[]`, @)
|
||||
message: "Контейнер '{{ element.name }}' использует runAsUser: 0 (root). Установите runAsUser >= 1000."
|
||||
deny:
|
||||
conditions:
|
||||
any:
|
||||
|
||||
@@ -30,11 +30,15 @@ spec:
|
||||
Добавьте в spec.securityContext:
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
pattern:
|
||||
spec:
|
||||
anyPattern:
|
||||
- spec:
|
||||
securityContext:
|
||||
seccompProfile:
|
||||
type: "RuntimeDefault | Localhost"
|
||||
type: RuntimeDefault
|
||||
- spec:
|
||||
securityContext:
|
||||
seccompProfile:
|
||||
type: Localhost
|
||||
|
||||
- name: disallow-unconfined-seccomp
|
||||
match:
|
||||
|
||||
@@ -28,5 +28,4 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: "{{ element.name }}"
|
||||
image: >-
|
||||
{{ replace_all('{{ element.image }}', ':latest', ':stable') }}
|
||||
image: "{{ replace_all(element.image, ':latest', ':stable') }}"
|
||||
@@ -41,12 +41,12 @@ spec:
|
||||
- list: "request.object.spec.containers"
|
||||
preconditions:
|
||||
any:
|
||||
- key: "{{ element.image }}"
|
||||
operator: Contains
|
||||
value: "openjdk-v1"
|
||||
- key: "{{ element.image }}"
|
||||
operator: Contains
|
||||
value: "eclipse-v1"
|
||||
- key: "{{ regex_match('openjdk-v1', element.image) }}"
|
||||
operator: Equals
|
||||
value: true
|
||||
- key: "{{ regex_match('eclipse-v1', element.image) }}"
|
||||
operator: Equals
|
||||
value: true
|
||||
patchStrategicMerge:
|
||||
spec:
|
||||
containers:
|
||||
|
||||
@@ -31,7 +31,7 @@ spec:
|
||||
audit.company.com/created-by: "{{ request.userInfo.username }}"
|
||||
audit.company.com/created-at: "{{ time_now_utc() }}"
|
||||
audit.company.com/user-groups: >-
|
||||
{{ request.userInfo.groups | join(', ', @) }}
|
||||
{{ join(', ', request.userInfo.groups) }}
|
||||
|
||||
- name: set-environment-labels
|
||||
match:
|
||||
|
||||
@@ -29,6 +29,9 @@ spec:
|
||||
configMap:
|
||||
name: kyverno-global-config
|
||||
namespace: kyverno
|
||||
- name: serviceType
|
||||
variable:
|
||||
value: "{{ request.object.metadata.labels.\"service-type\" || 'default' }}"
|
||||
mutate:
|
||||
foreach:
|
||||
- list: "request.object.spec.containers"
|
||||
@@ -38,7 +41,5 @@ spec:
|
||||
- name: "{{ element.name }}"
|
||||
resources:
|
||||
limits:
|
||||
+(memory): >-
|
||||
{{ globalConfig.data.\"{{ request.object.metadata.labels.\"service-type\" || 'default' }}_memory\" || '256Mi' }}
|
||||
+(cpu): >-
|
||||
{{ globalConfig.data.\"{{ request.object.metadata.labels.\"service-type\" || 'default' }}_cpu\" || '250m' }}
|
||||
+(memory): "{{ globalConfig.data.\"{{ serviceType }}_memory\" || '256Mi' }}"
|
||||
+(cpu): "{{ globalConfig.data.\"{{ serviceType }}_cpu\" || '250m' }}"
|
||||
|
||||
@@ -32,7 +32,6 @@ spec:
|
||||
namespace: "{{ request.object.metadata.name }}"
|
||||
synchronize: true
|
||||
data:
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
labels:
|
||||
generated-by: kyverno
|
||||
|
||||
@@ -24,6 +24,6 @@ spec:
|
||||
purpose: debug
|
||||
conditions:
|
||||
any:
|
||||
- key: "{{ time_since('', request.object.metadata.creationTimestamp, '') }}"
|
||||
- key: "{{ time_since('', target.metadata.creationTimestamp, '') }}"
|
||||
operator: GreaterThan
|
||||
value: "4h"
|
||||
value: "4h0s"
|
||||
|
||||
@@ -1,57 +1,114 @@
|
||||
# Другие варианты проверок
|
||||
#
|
||||
# проверить, что 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"
|
||||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: check-storage-class-approval
|
||||
annotations:
|
||||
policies.kyverno.io/title: "Проверка одобрения StorageClass"
|
||||
policies.kyverno.io/category: Governance
|
||||
policies.kyverno.io/severity: high
|
||||
policies.kyverno.io/subject: PersistentVolumeClaim
|
||||
policies.kyverno.io/description: >-
|
||||
Проверяет, что PVC использует StorageClass из одобренного списка.
|
||||
StorageClass считается одобренной, если имеет лейбл approved-for-production: "true".
|
||||
spec:
|
||||
validationFailureAction: Enforce
|
||||
background: false
|
||||
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:
|
||||
any:
|
||||
- key: "{{ storageClassInfo }}"
|
||||
operator: NotEquals
|
||||
value: "true"
|
||||
---
|
||||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: limit-deployments-per-namespace
|
||||
annotations:
|
||||
policies.kyverno.io/title: "Лимит Deployment в namespace"
|
||||
policies.kyverno.io/category: Governance
|
||||
policies.kyverno.io/severity: medium
|
||||
policies.kyverno.io/subject: Deployment
|
||||
policies.kyverno.io/description: >-
|
||||
Ограничивает количество Deployment в одном namespace до 20.
|
||||
Используется apiCall для подсчёта существующих деплойментов.
|
||||
spec:
|
||||
validationFailureAction: Enforce
|
||||
background: false
|
||||
rules:
|
||||
- name: check-deployment-count
|
||||
match:
|
||||
resources:
|
||||
kinds:
|
||||
- Deployment
|
||||
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 '{{ request.object.metadata.namespace }}' уже {{ existingDeployments }} деплойментов.
|
||||
Максимум разрешено 20.
|
||||
deny:
|
||||
conditions:
|
||||
any:
|
||||
- key: "{{ existingDeployments }}"
|
||||
operator: GreaterThanOrEquals
|
||||
value: "20"
|
||||
---
|
||||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: require-gpu-nodes-for-gpu-workloads
|
||||
annotations:
|
||||
policies.kyverno.io/title: "GPU workloads требуют GPU-нод"
|
||||
policies.kyverno.io/category: Resources
|
||||
policies.kyverno.io/severity: high
|
||||
policies.kyverno.io/subject: Pod
|
||||
policies.kyverno.io/description: >-
|
||||
Запрещает запускать GPU-workloads если в кластере меньше 2 GPU-нод.
|
||||
GPU-workload определяется лейблом workload-type: gpu на поде.
|
||||
spec:
|
||||
validationFailureAction: Enforce
|
||||
background: false
|
||||
rules:
|
||||
- name: check-gpu-nodes
|
||||
match:
|
||||
resources:
|
||||
kinds:
|
||||
- Pod
|
||||
selector:
|
||||
matchLabels:
|
||||
workload-type: gpu
|
||||
context:
|
||||
- name: gpuNodes
|
||||
apiCall:
|
||||
urlPath: "/api/v1/nodes"
|
||||
jmesPath: "items[?metadata.labels.\"node-type\" == 'gpu'].metadata.name"
|
||||
validate:
|
||||
message: >-
|
||||
GPU workloads требуют минимум 2 GPU-ноды в кластере.
|
||||
Текущее количество GPU-нод: {{ length(gpuNodes) }}.
|
||||
deny:
|
||||
conditions:
|
||||
any:
|
||||
- key: "{{ length(gpuNodes) }}"
|
||||
operator: LessThan
|
||||
value: "2"
|
||||
|
||||
@@ -1,33 +1,60 @@
|
||||
# Полезный паттерн — разные правила для CREATE и UPDATE
|
||||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: validate-deployment-operations
|
||||
annotations:
|
||||
policies.kyverno.io/title: "Разные проверки для CREATE и UPDATE"
|
||||
policies.kyverno.io/category: Governance
|
||||
policies.kyverno.io/severity: medium
|
||||
policies.kyverno.io/subject: Deployment
|
||||
policies.kyverno.io/description: >-
|
||||
Демонстрирует паттерн: разные правила для CREATE и UPDATE операций.
|
||||
При создании — обязательные лейблы app и team.
|
||||
При обновлении — запрет смены образа на тег latest.
|
||||
spec:
|
||||
validationFailureAction: Enforce
|
||||
background: false
|
||||
rules:
|
||||
- name: validate-on-create-only
|
||||
match:
|
||||
resources:
|
||||
kinds:
|
||||
- Deployment
|
||||
preconditions:
|
||||
any:
|
||||
- key: "{{ request.operation }}"
|
||||
operator: Equals
|
||||
value: CREATE
|
||||
validate:
|
||||
message: >-
|
||||
Новый Deployment '{{ request.object.metadata.name }}' должен иметь лейблы app и team.
|
||||
pattern:
|
||||
metadata:
|
||||
labels:
|
||||
app: "?*"
|
||||
team: "?*"
|
||||
|
||||
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 с изменением образа
|
||||
- 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:
|
||||
message: >-
|
||||
Образ изменён с '{{ request.oldObject.spec.template.spec.containers[0].image }}'
|
||||
на '{{ request.object.spec.template.spec.containers[0].image }}'.
|
||||
Запрещено использовать тег latest при обновлении образа.
|
||||
deny:
|
||||
conditions:
|
||||
any:
|
||||
- key: "{{ request.object.spec.template.spec.containers[0].image }}"
|
||||
operator: EndsWith
|
||||
value: ":latest"
|
||||
|
||||
@@ -31,24 +31,22 @@ spec:
|
||||
configMap:
|
||||
name: external-data-cache
|
||||
namespace: kyverno
|
||||
- name: allowedPattern
|
||||
variable:
|
||||
value: >-
|
||||
{{ join('', ['^(', join('|', split(allowedRegistries.data.\"allowed-registries\", '\n')[?@ != '']), ')']) }}
|
||||
validate:
|
||||
message: >-
|
||||
Образ '{{ element.image }}' из недоверенного реестра.
|
||||
Список разрешённых реестров (обновлён {{ allowedRegistries.data.\"last-updated\" }}):
|
||||
{{ allowedRegistries.data.\"allowed-registries\" }}
|
||||
foreach:
|
||||
- list: >-
|
||||
request.object.spec.containers[] |
|
||||
merge(request.object.spec.initContainers[] || `[]`, @)
|
||||
message: >-
|
||||
Образ '{{ element.image }}' из недоверенного реестра.
|
||||
Список разрешённых реестров (обновлён {{ allowedRegistries.data.\"last-updated\" }}):
|
||||
{{ allowedRegistries.data.\"allowed-registries\" }}
|
||||
deny:
|
||||
conditions:
|
||||
all:
|
||||
- key: "{{ element.image }}"
|
||||
operator: NotStartsWith
|
||||
value: "registry.company.com/"
|
||||
- key: "{{ element.image }}"
|
||||
operator: NotStartsWith
|
||||
value: "gcr.io/company-project/"
|
||||
- key: "{{ element.image }}"
|
||||
operator: NotStartsWith
|
||||
value: "public.ecr.aws/company/"
|
||||
- key: "{{ regex_match(allowedPattern, element.image) }}"
|
||||
operator: Equals
|
||||
value: false
|
||||
|
||||
Reference in New Issue
Block a user