Deckhouse Platform (DP) позволяет управлять безопасностью приложений в кластере с помощью набора политик, соответствующих модели Kubernetes Pod Security Standards и дополнительно расширяемых через встроенные механизмы DP.
Для реализации политик безопасности в DP используется Gatekeeper.
Применение Pod Security Standards
В DP поддерживаются три уровня политики безопасности:
privileged— неограничивающая политика с максимально широким уровнем разрешений;baseline— минимально ограничивающая политика, которая предотвращает наиболее известные и популярные способы повышения привилегий. Позволяет использовать стандартную (минимально заданную) конфигурацию пода;restricted— политика со значительными ограничениями. Предъявляет самые жесткие требования к подам.
Политика по умолчанию
По умолчанию используется политика baseline.
Она применяется к несистемным неймспейсам без лейбла security.deckhouse.io/pod-policy.
В версиях DP до v1.78 политика privileged применялась по умолчанию в кластерах, установленных с версией DP ниже v1.55, или если версию установки не удалось определить. Начиная с DP v1.78 политика по умолчанию — baseline независимо от версии установки кластера.
Если параметр enforcementAction имеет значение Deny, поды, не соответствующие политике baseline, отклоняются при пересоздании. Обновление таких кластеров до DP v1.78 блокируется, пока политика по умолчанию не задана явно.
Если модуль admission-policy-engine выключен, обновление не блокируется. После включения модуля применяется политика baseline.
Чтобы сохранить политику privileged, задайте её явно в параметре settings.podSecurityStandards.defaultPolicy.
Назначение политики
Варианты назначения политики:
- глобально — с помощью параметра
settings.podSecurityStandards.defaultPolicyмодуляadmission-policy-engine; -
для конкретного неймспейса — с помощью лейбла
security.deckhouse.io/pod-policy=<POLICY_NAME>.Пример команды для назначения политики
restrictedна все поды в неймспейсеmy-namespace:d8 k label ns my-namespace security.deckhouse.io/pod-policy=restricted
Режимы применения политики
Допустимые режимы применения политик:
deny— запрещает выполнение действий.dryrun— не влияет на выполнение действий и используется для отладки. Информацию о событиях можно посмотреть в веб-интерфейсе Deckhouse или с помощью командыd8 k.warn— работает какdryrun, но дополнительно выводит предупреждение с указанием причины, по которой бы произошёл запрет действия в режимеdeny.
По умолчанию политики Pod Security Standards в DP применяются в режиме deny.
В этом режиме поды приложений, не удовлетворяющие политикам, не могут быть запущены в кластере.
Как и в случае с назначением политик, режим их применения можно задать:
- глобально — с помощью параметра
settings.podSecurityStandards.enforcementActionмодуляadmission-policy-engine; -
для конкретного неймспейса — с помощью лейбла
security.deckhouse.io/pod-policy-action=<POLICY_ACTION>.Пример команды для установки режима
warnна все поды в неймспейсеmy-namespace:d8 k label ns my-namespace security.deckhouse.io/pod-policy-action=warn
Политики в системных неймспейсах
Неймспейсы с именами d8-* и kube-* содержат компоненты самой платформы.
Политики применяются к ним иначе, чем к прикладным неймспейсам, и это поведение не настраивается.
Создаваемые платформой неймспейсы дополнительно помечены лейблом heritage: deckhouse. Неймспейс с этим лейблом, но с другим именем не попадает под политики и мутации, написанные для прикладных неймспейсов; Pod Security Standards ниже действуют по именам.
Каждый неймспейс с именем d8-* или kube-* проверяется по стандарту restricted.
Лейбл security.deckhouse.io/pod-policy и параметр settings.podSecurityStandards.defaultPolicy в них не действуют.
Нарушение стандарта фиксируется в отчётах безопасности и отображается в веб-интерфейсе Deckhouse, нагрузка при этом запускается.
Исключение — неймспейс, в котором владеющий им модуль включил принудительное применение: там стандарты применяются, и нарушающая их нагрузка блокируется.
Настроить эти проверки извне платформы нельзя. Управляющие ими лейблы и сама нагрузка принадлежат владеющему неймспейсом модулю, и Deckhouse Platform возвращает их к заявленному состоянию при следующем применении конфигурации. Модуль сам выводит из-под проверки собственную нагрузку — ресурсом SecurityPolicyException, который поставляется вместе с модулем.
Ресурсы OperationPolicy и SecurityPolicy в системных неймспейсах тоже действуют в режиме warn.
Политика с enforcementAction: Deny блокирует запуск нагрузки в прикладных неймспейсах, а в системном неймспейсе только сообщает о нарушении.
Лейблы неймспейса на это не влияют: модуль, ужесточающий проверки в собственном неймспейсе, поднимает там Pod Security Standards, а к политике, написанной для прикладной нагрузки, это не относится.
Поэтому политика с enforcementAction: Deny, которая доходит до системных неймспейсов, разворачивается в два ограничения Gatekeeper, видимых в отчётах безопасности и в веб-интерфейсе Deckhouse:
- собственное имя политики — для прикладных неймспейсов, с тем действием, которое задано в политике;
d8-system-default-<политика>— для системных неймспейсов, в режимеwarn.
На период перехода к проверке контроллеров политика с enforcementAction: Deny по умолчанию только предупреждает о нарушениях в контроллерах, создающих поды.
Контроллеры проверяются ещё одним ограничением, d8-controllers-<политика>, в режиме warn, а ограничение с собственным именем политики проверяет только поды.
Параметр модуля podSecurityStandards.controllerValidationEnforcement: Policy или параметр политики spec.controllerValidation.mode: Enforce
включает проверку контроллеров с действием политики в одном ограничении.
Префиксы d8-system-default-, d8-pod-security- и d8-controllers- зарезервированы: политика, имя которой начинается с одного из них, отклоняется при создании.
По той же причине имя политики ограничено 235 символами: имена производных ограничений должны укладываться в 253 символа, отведённые для имени объекта Kubernetes.
Политика формируется как одно ограничение, когда разделение ничего не меняет:
- политика использует действие
WarnилиDryrun; - выбранные политикой неймспейсы не включают системные;
- политика уже исключает все выбранные ею системные неймспейсы;
- перечень неймспейсов использует маску в начале имени, например
*-system, которую нельзя точно пересечь сd8-*, — тогда единственное ограничение сохраняет действие политики и просто исключает системные неймспейсы; - политика выбирает только системные неймспейсы — тогда единственное ограничение сохраняет имя политики и только предупреждает о нарушениях.
Мутации Gatekeeper в системных неймспейсах не применяются, какие бы лейблы на неймспейсе ни стояли.
Платформа задаёт параметры своих компонентов сама, поэтому ресурсам Assign и ModifySet не разрешено изменять их параметры.
Расширение политики
Вы можете расширить политики baseline и restricted с помощью шаблонов Gatekeeper,
добавив необходимые проверки к уже существующим.
Чтобы расширить политику, выполните следующее:
- Создайте шаблон проверки с помощью
ConstraintTemplate. - Примените созданный шаблон к политике
baselineилиrestricted.
Пример шаблона для проверки адреса хранилища образов контейнеров:
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
у всех подов в неймспейсе с лейблом security.deckhouse.io/pod-policy: restricted.
Если адрес в поле image создаваемого пода начинается не с mycompany.registry.com, под создан не будет.
Вспомогательные ресурсы при создании расширенных политик:
- документация Gatekeeper с информацией о шаблонах и языке политик;
- библиотека Gatekeeper с примерами шаблонов проверок.
Операционные политики
DP предоставляет механизм создания операционных политик с помощью OperationPolicy. В операционных политиках задаются требования к объектам в кластере. Допустимые хранилища образов, требуемые ресурсы, наличие проб и т. д.
Команда разработки DP рекомендует установить следующую политику с минимально необходимым набором требований:
apiVersion: deckhouse.io/v1alpha1
kind: OperationPolicy
metadata:
name: common
spec:
policies:
allowedRepos:
- myrepo.example.com
- registry.deckhouse.ru
requiredResources:
limits:
- memory
requests:
- cpu
- memory
disallowedImageTags:
- latest
requiredProbes:
- livenessProbe
- readinessProbe
maxRevisionHistoryLimit: 3
imagePullPolicy: Always
priorityClassNames:
- production-high
- production-low
checkHostNetworkDNSPolicy: true
checkContainerDuplicates: true
match:
namespaceSelector:
labelSelector:
matchLabels:
operation-policy.deckhouse.io/enabled: "true"
Эта политика задаёт базовые операционные требования к объектам в кластере,
включая разрешённые хранилища образов контейнеров, обязательные ресурсы и пробы, запрет на использование образов с тегом latest,
допустимые классы приоритетов и другие настройки, повышающие безопасность и стабильность работы приложений.
Чтобы назначить данную операционную политику,
примените лейбл operation-policy.deckhouse.io/enabled=true к необходимому неймспейсу:
d8 k label ns my-namespace operation-policy.deckhouse.io/enabled=true
Политики безопасности
Используя SecurityPolicy, вы можете создавать политики безопасности, задающие ограничения на поведение контейнеров в кластере: доступ к host-сетям, привилегии, использование AppArmor и т. д.
Пример политики безопасности:
---
apiVersion: deckhouse.io/v1alpha1
kind: SecurityPolicy
metadata:
name: mypolicy
spec:
enforcementAction: Deny
policies:
allowHostIPC: true
allowHostNetwork: true
allowHostPID: false
allowPrivileged: false
allowPrivilegeEscalation: false
allowedFlexVolumes:
- driver: vmware
allowedHostPorts:
- max: 4000
min: 2000
allowedProcMount: Unmasked
allowedAppArmor:
- unconfined
allowedUnsafeSysctls:
- kernel.*
allowedVolumes:
- hostPath
- projected
fsGroup:
ranges:
- max: 200
min: 100
rule: MustRunAs
readOnlyRootFilesystem: true
requiredDropCapabilities:
- ALL
runAsGroup:
ranges:
- max: 500
min: 300
rule: RunAsAny
runAsUser:
ranges:
- max: 200
min: 100
rule: MustRunAs
seccompProfiles:
allowedLocalhostFiles:
- my_profile.json
allowedProfiles:
- Localhost
supplementalGroups:
ranges:
- max: 133
min: 129
rule: MustRunAs
match:
namespaceSelector:
labelSelector:
matchLabels:
enforce: mypolicy
Чтобы назначить данную политику безопасности,
примените лейбл enforce: "mypolicy" к необходимому неймспейсу.
Частичное применение политик
Чтобы применить отдельные политики безопасности, не отключая весь предустановленный набор, выполните следующие шаги:
- Добавьте на необходимый неймспейс лейбл
security.deckhouse.io/pod-policy: privileged, чтобы отключить встроенный набор политик. - Создайте SecurityPolicy, соответствующий уровню
baselineилиrestricted. В секцииpoliciesукажите только необходимые вам настройки безопасности. - Добавьте на неймспейс дополнительный лейбл, соответствующий селектору
namespaceSelectorв SecurityPolicy.
Пример конфигурации 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:
operation-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:
operation-policy.deckhouse.io/restricted-enabled: "true"
Кастомные ресурсы Gatekeeper
Gatekeeper предоставляет расширенные возможности для модификации ресурсов Kubernetes с помощью настраиваемых политик (mutation policies). Эти политики описываются через следующие кастомные ресурсы:
- AssignMetadata — для изменения секции
metadataв ресурсе; - Assign — для изменения других полей, кроме
metadata; - ModifySet — для добавления или удаления значений из списка, например, аргументов для запуска контейнера;
- AssignImage — для изменения параметра
imageресурса.
Подробнее о возможности изменения ресурсов Kubernetes с помощью настраиваемых политик можно прочитать в документации Gatekeeper.
Проверка подписи образов
Доступно в следующих редакциях DP: SE+, EE, Ultimate, Certified Core, Certified Pro.
Поддерживается Cosign не выше v2. Версии v3 и выше не поддерживаются.
DP поддерживает проверку подписей образов контейнеров с помощью инструмента Cosign.
Проверка подписи образов контейнеров позволяет убедиться в их целостности (что образ не был изменен после его создания) и подлинности (что образ был создан доверенным источником). Включить проверку подписи образов контейнеров в кластере можно с помощью параметра policies.verifyImageSignatures SecurityPolicy.
При подписании образа в хранилище образов контейнеров создается специальный тег, который содержит подпись образа.
Подпись формируется для хеш-суммы образа (дайджест образа). Например, для образа my-repo/app:latest с хешем sha256:abc123EXAMPLE, в хранилище образов появится образ my-repo/app:sha256-abc123EXAMPLE.sig. Таким образом, процесс подписи образа заключается в расчете и публикации дополнительного тега в хранилище образов контейнеров, без изменения существующего образа.
После подписания образа повторная его загрузка (push) в хранилище не требуется. Необходимо только авторизоваться в хранилище образов контейнеров с правами на запись.
Чтобы подписать образ с помощью Cosign, выполните следующее:
-
Убедитесь, что используется Cosign версии 2 или ниже.
Проверить версию:
cosign version.cosign version -
Сгенерируйте пару ключей (публичный и приватный):
cosign generate-key-pair -
Подпишите образ в хранилище образов контейнеров с помощью сгенерированного приватного ключа:
cosign sign --key <KEY> <REGISTRY_IMAGE_PATH>Здесь:
<REGISTRY_IMAGE_PATH>— путь к образу, который нужно указать при запуске, например,registry.private.ru/labs/application/image:latest.
Чтобы включить проверку подписи образов контейнеров в кластере DP:
-
Используйте параметр
policies.verifyImageSignaturesSecurityPolicy, указав сгенерированный публичный ключ.Пример конфигурации SecurityPolicy для проверки подписи образов контейнеров, размещенных в хранилище
registry.private.ruпо пути/labs/application/:apiVersion: deckhouse.io/v1alpha1 kind: SecurityPolicy metadata: name: verify-image-test spec: enforcementAction: Deny match: namespaceSelector: labelSelector: matchLabels: example-security-policy/enabled: true policies: allowHostIPC: true allowHostNetwork: true allowHostPID: false allowPrivilegeEscalation: true allowPrivileged: false allowRbacWildcards: true verifyImageSignatures: - publicKeys: - |- -----BEGIN PUBLIC KEY----- ... -----END PUBLIC KEY----- reference: registry.private.ru/labs/application/*Название лейбла, указанного в
match.namespaceSelector.labelSelector.matchLabels, может быть любым. Лейбл в селекторе политики должен совпадать с лейблом соответствующего неймспейса.Подробнее — в разделе «Как настроить селекторы политик».
-
Создайте OperationPolicy, ограничивающий запуск подов из сторонних хранилищ образов:
apiVersion: deckhouse.io/v1alpha1 kind: OperationPolicy metadata: name: test-operation-policy spec: enforcementAction: Deny match: namespaceSelector: labelSelector: matchLabels: example-operation-policy/enabled: "true" policies: allowedRepos: - registry.private.ruНазвание лейбла, указанного в
match.namespaceSelector.labelSelector.matchLabels, может быть любым. Лейбл в селекторе политики должен совпадать с лейблом соответствующего неймспейса.Подробнее — в разделе «Как настроить селекторы политик».
-
Добавьте лейбл на неймспейс, в котором нужно включить проверку подписи (укажите нужный неймспейс):
d8 k label ns <NAMESPACE> example-security-policy/enabled=true -
Добавьте лейбл на неймспейс, в котором нужно ограничить запуск подов из сторонних хранилищ образов (укажите нужный неймспейс):
d8 k label ns <NAMESPACE> example-operation-policy/enabled=true -
Для проверки работы механизма подписи образов разверните в неймспейсе поды с подписанным и неподписанным образами (укажите нужный неймспейс):
d8 k -n <NAMESPACE> run signed-pod --image=<SIGNED_IMAGE> d8 k -n <NAMESPACE> run unsigned-pod --image=<UNSIGNED_IMAGE>
Согласно данной политике, если адрес какого-либо образа контейнера совпадает со значением параметра reference и образ не подписан или подпись не соответствует указанным ключам, создание пода будет запрещено.
Пример вывода ошибки при создании пода с образом контейнера, не прошедшим проверку подписи:
[verify-image-signatures] Image signature verification failed: nginx:1.17.2
Использование альтернатив для управления политиками безопасности
Если вместо встроенного механизма управления политиками безопасности в кластере DP используется альтернативное решение (например, Kyverno), настройте исключения для следующих неймспейсов:
kube-system;- все неймспейсы с префиксом
d8-*(например,d8-system).
Без этих исключений политики могут блокировать или нарушать работу системных компонентов.