![](https://habrastorage.org/getpro/habr/upload_files/b02/64f/81c/b0264f81c75e71d8e28421683c4ffd44.png)
![](https://habrastorage.org/getpro/habr/upload_files/851/40d/702/85140d702b32fd17af39d01e89af7624.jpg)
Автор статьи: Рустем Галиев
IBM Senior DevOps Engineer & Integration Architect. Официальный DevOps ментор и коуч в IBM
Привет Хабр!
Сперва небольшая вводная:
AppArmor — это модуль безопасности ядра Linux, который дополняет стандартные разрешения Linux для пользователей и групп, ограничивая программы набором ресурсов. AppArmor можно настроить для любого приложения, чтобы уменьшить потенциальную поверхность атаки и обеспечить более глубокую защиту. Он настраивается с помощью профилей, настроенных так, чтобы разрешить доступ, необходимый для конкретной программы или контейнера, например возможности Linux, доступ к сети, права доступа к файлам и т. д. Каждый профиль можно запускать либо в принудительном режиме, который блокирует доступ к запрещенным ресурсам, либо в режиме жалобы - режим, который сообщает только о нарушениях.
AppArmor может помочь вам выполнить более безопасное развертывание, ограничив возможности контейнеров и/или предоставив лучший аудит с помощью системных журналов. Однако важно иметь в виду, что AppArmor не является серебряной пулей и может сделать очень мало для защиты от эксплойтов в коде вашего приложения.
AppArmor обеспечивает контроль доступа к программам, работающим в системе Linux. Инструмент реализует дополнительный уровень безопасности между приложениями, вызываемыми в пользовательском пространстве и базовой функциональностью системы. Например, мы можем ограничить сетевые вызовы или взаимодействие с файловой системой. Многие дистрибутивы Linux (например, Debian, Ubuntu, openSUSE) уже поставляются с AppArmor. Поэтому AppArmor не нужно устанавливать вручную.
Важная концепция в AppArmor - это профили
Правила определяющие, что программа может или не может делать, определяются в профиле AppArmor. Каждый профиль должен быть загружен в AppArmor, прежде чем он начнет действовать. AppArmor предоставляет инструмент командной строки для проверки загруженных профилей. Мы можем выполнить команду aa-status
, чтобы увидеть сводку всех загруженных профилей. Увидим, что AppArmor уже поставляется с набором профилей приложений по умолчанию для защиты служб Linux:
![](https://habrastorage.org/getpro/habr/upload_files/3ec/37b/759/3ec37b759d4563496eb5b869456b44b5.png)
Режим профиля определяет обработку правил во время выполнения, если произойдет соответствующее событие. AppArmor различает два типа режимов профиля:
Enforce: Система применяет правила, сообщает о нарушении и записывает его в системный журнал. Мы используем этот режим, чтобы запретить программе выполнять определенные вызовы.
Complain: Система не применяет правила, но записывает нарушения в журнал. Этот режим полезен, если мы хотим обнаружить вызовы, которые делает программа.
Например это определяет пользовательский профиль в файлеk8s-deny-write
для ограничения доступа к файлу на запись. Файл должен быть помещен в директорию/etc/apparmor.d
каждого рабочего узла, выполняющего рабочую нагрузку.
#include <tunables/global>
profile k8s-deny-write flags=(attach_disconnected) {
#include <abstractions/base>
file,
deny /** w,
}
Чтобы загрузить профиль в AppArmor, мы запускаем следующую команду на рабочем узле: sudo apparmor_parser /etc/apparmor.d/k8s-deny-write
По умолчанию команда использует enforce режим. Чтобы загрузить профиль в режиме complain, используйте параметр -C
. Команда aa-status
теперь будет отображать профиль в дополнение к профилям по умолчанию. Как вы можете видеть в выводе, профиль указан в принудительном режиме:
![](https://habrastorage.org/getpro/habr/upload_files/c2e/a40/a75/c2ea40a757c5c195e0053f2f44a11220.png)
С теорией разобрались, давайте теперь поработаем с ним.
Мы создадим профиль AppArmor с именем network-deny в текущей директории, который предотвращает любой входящий и исходящий сетевой трафик и добавим профиль в набор правил AppArmor в принудительном режиме на node01
.
Также у нас будет под со следующим дескриптором:
apiVersion: v1
kind: Pod
metadata:
name: network-call
spec:
containers:
- name: network-call
image: alpine/curl:3.14
command: ["sh", "-c", "while true; do ping -c 1 google.com; sleep 5; done"]
Создадим его и проверим
![](https://habrastorage.org/getpro/habr/upload_files/468/ffa/28c/468ffa28c2e188d0b52a254143db23bf.png)
![](https://habrastorage.org/getpro/habr/upload_files/9f0/7fa/699/9f07fa699ade698c0052ad407566bce7.png)
Окей, приступим.
Перейдем на рабочий узел node01
.
$ ssh node01
![](https://habrastorage.org/getpro/habr/upload_files/714/99c/8df/71499c8df0044b531b5b5c5b4678085a.png)
Создадим профиль AppArmor в /etc/apparmor.d/network-deny
. Содержимое файла должно выглядеть следующим образом:
#include <tunables/global>
profile network-deny flags=(attach_disconnected) {
#include <abstractions/base>
network,
}
Применим профиль AppArmor, выполнив следующую команду:apparmor_parser /etc/apparmor.d/network-deny
![](https://habrastorage.org/getpro/habr/upload_files/260/47f/4d4/26047f4d45f3402f1343ec1cadd7e3c0.png)
Ну и вернемся на controlplane
![](https://habrastorage.org/getpro/habr/upload_files/065/32e/e8e/06532ee8e7aab109f2c68c972dd33333.png)
Прежде чем использовать правила AppArmor в дескрипторе пода, необходимо выполнить несколько предварительных условий. Во-первых, среда выполнения контейнера должна поддерживать AppArmor, чтобы правила вступили в силу. Кроме того, AppArmor необходимо установить на рабочем узле, на котором работает под.
Мы не можем изменить существующий объект Pod, чтобы добавить аннотацию для AppArmor. Сначала вам нужно удалить объект.
![](https://habrastorage.org/getpro/habr/upload_files/2f7/41c/2b8/2f741c2b8a25f8c91efdd1f8d2c0f6c6.png)
Чтобы применить профиль к контейнеру, нам нужно будет установить определенную аннотацию. Ключ аннотации должен использовать ключ в формате container.apparmor.security.beta.kubernetes.io/<container-name>
Редактируем файл pod.yaml
в текущей директории. Добавляем аннотацию AppArmor. Для соответствующей аннотации мы используем имя контейнера network-call
как часть ключевого суффикса и localhost/network-deny
в качестве значения. Суффикс network-deny
относится к имени профиля AppArmor. Окончательное содержание файла будет выглядеть следующим образом:
apiVersion: v1
kind: Pod
metadata:
name: network-call
annotations:
container.apparmor.security.beta.kubernetes.io/network-call: localhost/network-deny
spec:
containers:
- name: network-call
image: alpine/curl:3.14
command: ["sh", "-c", "while true; do ping -c 1 google.com; sleep 5; done"]
Создадим под
![](https://habrastorage.org/getpro/habr/upload_files/fb6/776/96d/fb677696de1a66b3fb01089fc7df43d9.png)
AppArmor не позволяет поду совершать сетевые вызовы. Но мы проверим логи, чтобы убедиться в этом:
![](https://habrastorage.org/getpro/habr/upload_files/009/233/951/009233951656d7b40fa8e66a6affbd86.png)
Напоследок хочу порекомендовать бесплатный вебинар, на котором вы узнаете из каких компонентов состоит Kubernetes, как они взаимодействуют и для чего нужны, а также подробно познакомитесь с базовыми объектами, которые существуют внутри любого кластера Kubernetes.
vasyakrg
Не очень понял, зачем задачу прав в кубе решать нативно средствами операционки ?
А если у меня 100 нод в кубе - ансом профили раскатывать каждый раз ?
А если куб из мульти-нод ? Часть нод на винде вообще, часть в облаке, где по ssh на ноду просто так не сходишь и нужно городить шелл-поды.
В кубах есть куча инструментов, правил и политик: и сетевых и на выполнение действий, которые прекрасно с этим справляются, абстрагируя хождение в операционку (и имеющие собственно все это самое под капотом)
Numen_Divinum
..и AppArmor - один из них
Входит в требования CIS и программу сертификации CKS, если что