Это вторая статья из цикла


Сегодня мы поговорим о SELinux-пользователях, их создании, привязке, правам и другим вещам.

Зачем это делать? Есть много причин. Для меня главной причиной было выдать доступ для техподдержки для рутинных операций (таких как ребут, чистка логов, диагностика итд), но без доступа к критичным данным и изменению системных функций.

Предположения


В тексте будет содержаться много технической информации, поэтому автор предполагает, что читатель:

  • Прочитал прошлую статью
  • Имеет под рукой CentOS 7
  • На котором установлены пакеты setools-console, policycoreutils-devel, selinux-policy-devel, policycoreutils-newrole
  • И включен SELinux в режиме enforcing с политикой targeted или minimum

Это все про вас? Тогда поехали!

Пользователи и роли


Основное назначение пользователей — хранить список ролей, которые он может использовать.
Пользователи по-умолчанию уже представлены в политике targeted или minimum, можете посмотреть командой semanage user -l.



Как известно из прошлой статьи, именно роли являются контейнерами для типов, а именно на типы вешаются все необходимые правила.

Таким образом, пользователь просто расширяет это дерево, создавая больше возможных вариантов. Обратите внимание: если у пользователя есть та или иная роль, он может самостоятельно переключиться в нее, используя команду newrole. Таким образом, разрешив пользователю роль sysadm_r или unconfined_r, вы автоматически даете ему неограниченные права на систему.

Пользователи и пользователи


Между Unix-пользователем (тем, который имеет UID) и SELinux-пользователем (тем, который имеет контекст) есть тонкая связь, которой можно управлять при помощи команды semanage login. Связь это односторонняя: id -Z user1 вам ничего не покажет. Специальный пользователь __default__ обозначает всех пользователей, не перечисленных в системе.



Создание пользователя (простой способ)


Самый простой способ создать пользователя из готовых ролей — использовать semanage user -a.

Предположим, нам нужен просто новый пользователь с дополнительным набором ролей:



Таким образом мы получили пользователя, который имеет возможность админить web. Теперь мы можем задать для него пользователя:



Контекст


Об этом мало где пишут, но мало просто создать пользователя. Если его контекст отличается от default_context, для него необходимо настроить файл контекстов. Подробнее см. man user_contexts.

Настроим файл и для webadm_u:



Проверка


Зайдем под пользователем webadm:



Сменим uid на 0 и попробуем что-нибудь «сломать»:



Сменим роль на webadm_r и попробуем теперь:



Что и требовалось доказать — мы сделали админа, который может админить только веб. К сожалению, количество ролей «по-умолчанию» сильно ограничено. Список можно посмотреть тут.

Создание пользователя (правильный способ)


Давайте сделаем все тоже самое, но например для администрирования docker, причем напишем его с нуля.

Модуль будет очень простой. Что нам нужно разрешить?

  1. Вход по ssh
  2. Доступ к sudo (UNIX-права никто не отменял)*
  3. Администрирование файлов, папок и сервиса докера
  4. Исполнение бинарников докера (docker, runcon)
  5. Коннект к сокету докера

*
Группа docker на последней версии CentOS7 не имеет доступа к /run/docker.sock по-умолчанию.

Напишем модуль и контекст-файл:

# новый модуль
policy_module(dockeradm, 1.0.3)
# объявляем новую роль
role dockeradm_r;
# стандартный шаблон для НЕ-админа
userdom_unpriv_user_template(dockeradm)
# разрешаем dac_override
allow dockeradm_t self:capability { dac_override dac_read_search };
# разрешаем sudo
sudo_role_template(dockeradm, dockeradm_r, dockeradm_t)
# разрешаем управлять файлами и папками контейнеров
container_admin(dockeradm_t)
# разрешаем исполнять исполняемые файлы контейнера
container_runtime_exec(dockeradm_t)
# разрешаем коннект к сокетам контейнера
container_stream_connect(dockeradm_t)
# макрос gen_user создает пользователя так-же, как semanage user -a
# он всегда должен быть в самом конце файла
gen_user(dockeradm_u, dockeradm, dockeradm_r, s0, s0)

Скомпилируем и установим модуль:



Настроим пользователя и контекст:



Проверим, что нас пускает в систему:



Проверим наши права:



Как говорит Apache, It works!

Подведение итогов


Создание SELinux-пользователей — важный шаг к созданию полноценного рабочего окружения, в котором каждый сотрудник занимается своим делом и при этом не мешает другим. Будь то хостинг-провайдер, студия разработки или банк, всегда есть ситуации, когда разделение доступа необходимо. Включайте SELinux и наслаждайтесь :)
Поделиться с друзьями
-->

Комментарии (20)


  1. kreon
    26.02.2017 14:46

    «Обилие» комментариев может говорить о двух вещах:
    — Эта тема никому не интересна
    — Из материала все настолько ясно, что и добавить нечего.

    Я планировал написать еще несколько статей на эту тему, поправьте меня, если я зря это делаю :)


    1. grossws
      27.02.2017 04:45

      Тема selinux интересна (хотя мне пока более интересна ваша прошлая статья), материала на русском по selinux довольно мало, так что пишите дальше.


      Для меня пока может оказаться актуальным завернуть некоторые сервисы, но полноценный rbac мне пока не нужен.


      А какие ещё темы вы собирались осветить?


      1. kreon
        27.02.2017 08:00
        +1

        — Настройка базовой refpolicy на примере LAMP ( booleans, contexts, etc )
        — Читшит по макросам refpolicy ( самому надо :) )
        — Возможно — внедрение MLS/MCS, но это уже больше для банков и прочих военных.


        1. bugrazoid
          28.02.2017 16:29

          Хотелось бы про — внедрение MLS/MCS.


      1. acmnu
        27.02.2017 11:38

        "Некоторые сервисы" гораздо проще оборачивать в правильно собранные контейнеры. Это даст довольно высокую защиту от эксплуатации удаленных уязвимостей (банально запрет изменения fs контейнера, отсутствие лишних исполнимых файлов и т.д.)


        SELinux это впервую очередь rbac, который нужен очень мало кому и широко он распространнен не на серверах, а на телефонах с Android.


        1. grossws
          27.02.2017 20:25

          "Некоторые сервисы" гораздо проще оборачивать в правильно собранные контейнеры. Это даст довольно высокую защиту от эксплуатации удаленных уязвимостей (банально запрет изменения fs контейнера, отсутствие лишних исполнимых файлов и т.д.)

          Если приложение не легкий сервис на golang, то правильно его упаковать в контейнер не оставив лишних бинарников может быть крайне нетривиальной задачей. Хотя базово сейчас можно соблюдать элементарную гигиену типа запуска сервиса под пользователем, private tmp, явного определение rw/ro/inaccessible путей (соответственно используется filesystem ns) декларативно при использовании systemd. Всякие вещи типа зарезания capabilities и seccomp вполне доступны через тот systemd, но требует уже гораздо количества геморроя, если сервису надо стартовать не под непривилегерованным пользователем.


          1. acmnu
            28.02.2017 12:40

            Если приложение не легкий сервис на golang, то правильно его упаковать в контейнер не оставив лишних бинарников может быть крайне нетривиальной задачей.

            Да это так. Но мне кажется, что эта проблема сопоставима со сложностью написания качественных конфигов SELinux.


            1. kreon
              28.02.2017 12:46

              В идеальном мире полиси пишется разработчиками, которые точно знают, что их софт хочет и будет делать.
              В не-идеальном — semanage permissive -a, sleep 86400, audit2allow -b -t software_t и курим что он делал и что из этого ему реально надо.


              1. acmnu
                28.02.2017 12:53

                Для этого надо иметь тесты, которые покроют полную функциональность, чтоб в продакшене не стрельнуло. Отыскать список необходимых сошников для apache и положить их в контейнер несколько проще.


        1. kreon
          27.02.2017 21:09

          Помимо подчас ненужного оверхеда и сложных конфигураций, есть простой вопрос: зачем?
          Зачем тот-же LAMP засовывать в контейнеры ( причем еще каждый компонент в свой ), когда можно просто настроить контексты за 10 минут и спать спокойно?


          1. acmnu
            28.02.2017 12:05

            Это проще и легко повторимо (через сборку контейнеров), в отличии от контекстов.


            1. kreon
              28.02.2017 12:06

              Если мы говорим про повторимость — то все вообще делает паппет/ансибл/чиф.


              1. acmnu
                28.02.2017 12:18

                Ой, нет. Не делают они это. Как раз папет и ансибл моя прямая обязанность нынче. Поверть мне, если вы начали использовать такие вещи, то значит вы уперлись в некую безнадегу. Если есть возможность запакетировать в rpm, docker или ещё какой-нибудь статический вид, то без сомнения делайте это. Если ваша программа может использовать некую онлайн базу конфигурации (etcd, ldap, mysql), то делайте это, не используйте паппет с хиерой. Вообще никогда не используйте паппет. Не при каких обстоятельствах, а ансибл там где без него никак не обойтись (например обновление, оркестрирование некими переходными процессами ну и прочие процедуры без внутренних состояний).


                1. kreon
                  28.02.2017 12:20

                  Зависит от маштабов. Тот-же селинукс я прекрасно заворачиваю в паппет и раскидываю по тысячам серверов. И все отлично работает :)


                  1. acmnu
                    28.02.2017 12:37
                    +1

                    Да ладно отлично. Никогда не сталкивались с проблемой обеспечения идемпотентонсти в папет модулях? Или проблематике переходного процесса с разными состояниями одного объекта, когда нельзя задать цепочку service stop -> package update -> service start (обходные пути есть, это самый популярный вопрос по папет на стаковерфлоу)? Или проблема многократного запуска, когда невозможно в один проход получить все факты о системе (софт А генерирует уникальные ID, которые надо отдать софту B на другом сервере). А логирование ошибок как вам, особенно когда она где-то глубоко в ruby коде, который написан третьей стороной?


                    Короче мне тут на любимую мазоль наступили, которая на целую статью потянет наверное, но писать её боюсь (срача много, толку мало).


                    1. kreon
                      28.02.2017 12:38

                      Сталкивались. Приходите к нам работать — научим :)


                      1. acmnu
                        28.02.2017 12:49

                        "Ой! Ну вас, Василий Иваныч! Всё-то вы только обещаете." Я никогда не видел хорошего специалиста по паппет. Видел много людей, которые думают, что они хорошие специалисты, но это не так.


                        1. kreon
                          28.02.2017 17:06

                          И да, часть этих проблем решает puppet4 :)


                    1. kreon
                      28.02.2017 17:05

                      А статью кстати напишите. Дискуссия поможет найти истину :)


    1. grumbler66rus
      28.02.2017 22:06

      Очень интересно и нужно. IMHO это реально хороший how-to, даже на английском я не видел такого качественного руководства, где нет лишнего и всё понятно.
      Я только сегодня получил вашу статью в рассылке