Стадия жизненного цикла модуля: General Availability
Как настроить альтернативные решения по управлению политиками безопасности?
Для корректной работы DKP необходимы расширенные привилегии на запуск и работу полезной нагрузки системных компонентов. Если вместо модуля admission-policy-engine используется альтернативное решение по управлению политиками безопасности (например, Kyverno), необходима настройка исключений для следующих пространств имен:
kube-system;- все пространства имен с префиксом
d8-*(например,d8-system).
Как расширить политики Pod Security Standards?
Pod Security Standards реагируют на label security.deckhouse.io/pod-policy: restricted или security.deckhouse.io/pod-policy: baseline.
Чтобы расширить политику Pod Security Standards, добавив к существующим проверкам политики свои собственные, необходимо:
- создать шаблон проверки (
ConstraintTemplate); - привязать его к политике
restrictedилиbaseline.
Пример шаблона для проверки адреса репозитория образа контейнера:
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8sallowedrepos
spec:
crd:
spec:
names:
kind: K8sAllowedRepos
validation:
openAPIV3Schema:
type: object
properties:
repos:
type: array
items:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package d8.pod_security_standards.extended
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
satisfied := [good | repo = input.parameters.repos[_] ; good = startswith(container.image, repo)]
not any(satisfied)
msg := sprintf("container <%v> has an invalid image repo <%v>, allowed repos are %v", [container.name, container.image, input.parameters.repos])
}
violation[{"msg": msg}] {
container := input.review.object.spec.initContainers[_]
satisfied := [good | repo = input.parameters.repos[_] ; good = startswith(container.image, repo)]
not any(satisfied)
msg := sprintf("container <%v> has an invalid image repo <%v>, allowed repos are %v", [container.name, container.image, input.parameters.repos])
}
Пример привязки проверки к политике restricted:
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sAllowedRepos
metadata:
name: prod-repo
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
namespaceSelector:
matchLabels:
security.deckhouse.io/pod-policy: restricted
parameters:
repos:
- "mycompany.registry.com"
Пример демонстрирует настройку проверки адреса репозитория в поле image у всех подов, создающихся в пространстве имен, имеющих label security.deckhouse.io/pod-policy: restricted. Если адрес в поле image создаваемого пода начинается не с mycompany.registry.com, под создан не будет.
Подробнее о шаблонах и языке политик можно узнать в документации Gatekeeper.
Больше примеров описания проверок для расширения политики можно найти в библиотеке Gatekeeper.
Как включить одну или несколько политик Pod Security Standards, не отключая весь набор?
Чтобы применить только нужные политики безопасности, не отключая весь предустановленный набор:
- Добавьте в нужное пространство имён метку:
security.deckhouse.io/pod-policy: privileged, чтобы отключить встроенный набор политик. - Создайте SecurityPolicy, соответствующий уровню baseline или restricted. В секции
policiesукажите только необходимые вам настройки. - Добавьте в пространство имён дополнительную метку, которая будет соответствовать селектору
namespaceSelectorв SecurityPolicy. В примерах ниже этоsecurity-policy.deckhouse.io/baseline-enabled: "true"либоsecurity-policy.deckhouse.io/restricted-enabled: "true"
SecurityPolicy, соответствующая baseline:
apiVersion: deckhouse.io/v1alpha1
kind: SecurityPolicy
metadata:
name: baseline
spec:
enforcementAction: Deny
policies:
allowHostIPC: false
allowHostNetwork: false
allowHostPID: false
allowPrivilegeEscalation: true
allowPrivileged: false
allowedAppArmor:
- runtime/default
- localhost/*
allowedCapabilities:
- AUDIT_WRITE
- CHOWN
- DAC_OVERRIDE
- FOWNER
- FSETID
- KILL
- MKNOD
- NET_BIND_SERVICE
- SETFCAP
- SETGID
- SETPCAP
- SETUID
- SYS_CHROOT
allowedHostPaths: []
allowedHostPorts:
- max: 0
min: 0
allowedProcMount: Default
allowedUnsafeSysctls:
- kernel.shm_rmid_forced
- net.ipv4.ip_local_port_range
- net.ipv4.ip_unprivileged_port_start
- net.ipv4.tcp_syncookies
- net.ipv4.ping_group_range
- net.ipv4.ip_local_reserved_ports
- net.ipv4.tcp_keepalive_time
- net.ipv4.tcp_fin_timeout
- net.ipv4.tcp_keepalive_intvl
- net.ipv4.tcp_keepalive_probes
seLinux:
- type: ""
- type: container_t
- type: container_init_t
- type: container_kvm_t
- type: container_engine_t
seccompProfiles:
allowedProfiles:
- RuntimeDefault
- Localhost
- undefined
- ''
allowedLocalhostFiles:
- '*'
match:
namespaceSelector:
labelSelector:
matchLabels:
security-policy.deckhouse.io/baseline-enabled: "true"
SecurityPolicy, соответствующая restricted:
apiVersion: deckhouse.io/v1alpha1
kind: SecurityPolicy
metadata:
name: restricted
spec:
enforcementAction: Deny
policies:
allowHostIPC: false
allowHostNetwork: false
allowHostPID: false
allowPrivilegeEscalation: false
allowPrivileged: false
allowedAppArmor:
- runtime/default
- localhost/*
allowedCapabilities:
- NET_BIND_SERVICE
allowedHostPaths: []
allowedHostPorts:
- max: 0
min: 0
allowedProcMount: Default
allowedUnsafeSysctls:
- kernel.shm_rmid_forced
- net.ipv4.ip_local_port_range
- net.ipv4.ip_unprivileged_port_start
- net.ipv4.tcp_syncookies
- net.ipv4.ping_group_range
- net.ipv4.ip_local_reserved_ports
- net.ipv4.tcp_keepalive_time
- net.ipv4.tcp_fin_timeout
- net.ipv4.tcp_keepalive_intvl
- net.ipv4.tcp_keepalive_probes
allowedVolumes:
- configMap
- csi
- downwardAPI
- emptyDir
- ephemeral
- persistentVolumeClaim
- projected
- secret
requiredDropCapabilities:
- ALL
runAsUser:
rule: MustRunAsNonRoot
seLinux:
- type: ""
- type: container_t
- type: container_init_t
- type: container_kvm_t
- type: container_engine_t
seccompProfiles:
allowedProfiles:
- RuntimeDefault
- Localhost
allowedLocalhostFiles:
- '*'
match:
namespaceSelector:
labelSelector:
matchLabels:
security-policy.deckhouse.io/restricted-enabled: "true"
Что, если несколько политик (операционных или безопасности) применяются на один объект?
В этом случае необходимо, чтобы конфигурация объекта соответствовала всем политикам, которые на него распространяются.
Например, рассмотрим две следующие политики безопасности:
apiVersion: deckhouse.io/v1alpha1
kind: SecurityPolicy
metadata:
name: foo
spec:
enforcementAction: Deny
match:
namespaceSelector:
labelSelector:
matchLabels:
name: test
policies:
readOnlyRootFilesystem: true
requiredDropCapabilities:
- MKNOD
---
apiVersion: deckhouse.io/v1alpha1
kind: SecurityPolicy
metadata:
name: bar
spec:
enforcementAction: Deny
match:
namespaceSelector:
labelSelector:
matchLabels:
name: test
policies:
requiredDropCapabilities:
- NET_BIND_SERVICE
Тогда для выполнения требований приведенных политик безопасности в спецификации контейнера нужно указать:
securityContext:
capabilities:
drop:
- MKNOD
- NET_BIND_SERVICE
readOnlyRootFilesystem: true
Проверка подписи образов
Доступно в следующих редакциях DKP: SE+, EE, CSE Lite (1.67), CSE Pro (1.67).
Поддерживается Cosign не выше v2. Версии v3 и выше не поддерживаются.
В модуле реализована функция проверки подписи образов контейнеров, подписанных с помощью инструмента Cosign. Подробнее о подписании и проверке образов контейнеров можно узнать в документации DKP.
Как запретить удаление узла без метки
Примечание. Операции DELETE обрабатываются Gatekeeper по умолчанию.
Можно создать собственную политику Gatekeeper, запрещающую удаление узла без специальной метки. Пример ниже использует oldObject для проверки меток удаляемого узла:
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: d8customnodedeleteguard
spec:
crd:
spec:
names:
kind: D8CustomNodeDeleteGuard
validation:
openAPIV3Schema:
type: object
properties:
requiredLabelKey:
type: string
requiredLabelValue:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package d8.custom
is_delete { input.review.operation == "DELETE" }
is_node { input.review.kind.kind == "Node" }
has_required_label {
key := input.parameters.requiredLabelKey
val := input.parameters.requiredLabelValue
obj := input.review.oldObject
obj.metadata.labels[key] == val
}
violation[{"msg": msg}] {
is_delete
is_node
not has_required_label
msg := sprintf("Удаление Node запрещено. Добавьте метку %q=%q.", [input.parameters.requiredLabelKey, input.parameters.requiredLabelValue])
}
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: D8CustomNodeDeleteGuard
metadata:
name: require-node-delete-label
spec:
enforcementAction: warn
match:
kinds:
- apiGroups: [""]
kinds: ["Node"]
parameters:
requiredLabelKey: "admission.deckhouse.io/allow-delete"
requiredLabelValue: "true"