Как я могу сказать SELinux разрешить nginx доступ к сокету unix без audit2allow?

9

У меня nginx перенаправляет запросы на gunicorn через сокет unix на /run/gunicorn/socket. По умолчанию это поведение не разрешено SELinux:

grep nginx /var/log/audit/audit.log
type=SERVICE_START msg=audit(1454358912.455:5390): pid=1 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:init_t:s0 msg='unit=nginx comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'
type=AVC msg=audit(1454360194.623:7324): avc:  denied  { write } for  pid=9128 comm="nginx" name="socket" dev="tmpfs" ino=76151 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:httpd_sys_content_t:s0 tclass=sock_file
type=SYSCALL msg=audit(1454360194.623:7324): arch=c000003e syscall=42 success=no exit=-13 a0=c a1=1f6fe58 a2=6e a3=7ffee1da5710 items=0 ppid=9127 pid=9128 auid=4294967295 uid=995 gid=993 euid=995 suid=995 fsuid=995 egid=993 sgid=993 fsgid=993 tty=(none) ses=4294967295 comm="nginx" exe="/usr/sbin/nginx" subj=system_u:system_r:httpd_t:s0 key=(null)
type=AVC msg=audit(1454361591.701:13343): avc:  denied  { connectto } for  pid=9128 comm="nginx" path="/run/gunicorn/socket" scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:system_r:initrc_t:s0 tclass=unix_stream_socket
type=SYSCALL msg=audit(1454361591.701:13343): arch=c000003e syscall=42 success=no exit=-13 a0=c a1=1f6fe58 a2=6e a3=7ffee1da5950 items=0 ppid=9127 pid=9128 auid=4294967295 uid=995 gid=993 euid=995 suid=995 fsuid=995 egid=993 sgid=993 fsgid=993 tty=(none) ses=4294967295 comm="nginx" exe="/usr/sbin/nginx" subj=system_u:system_r:httpd_t:s0 key=(null)

Куда бы я ни посмотрел (например, здесь и здесь ), инструкции по включению этого слова, чтобы сделать запрос к nginx, должны были отклонить запрос SELinux, а затем выполнить, audit2allowчтобы разрешить будущие запросы. Я не могу понять ни одну команду chconили semanageкоманду, которая позволяет это поведение явно.

Это единственный способ? Кажется смешным, что вы не можете установить политику, которая позволяет nginx записывать в сокет без предварительной попытки, а затем без запуска инструмента, который разрешает запрещенные вещи. Как вы точно знаете, что включено? Как это должно работать, если вы настраиваете машины под автоматизацию?

Я использую CentOS 7.

DRS
источник
Вам нужно показать нам сообщения об отказе AVC, и было бы хорошо узнать, какую ОС и версию вы используете.
user9517
@ Хорошая мысль.
DRS

Ответы:

23

Кажется смешным, что вы не можете установить политику, которая позволяет nginx записывать в сокет без предварительной попытки, а затем без запуска инструмента, который разрешает запрещенные вещи.

Нет, SELinux - это обязательный контроль доступа, по умолчанию все запрещено, и вы должны явно что-то разрешить. Если авторы политики не рассматривали конкретный (откровенный) стек или авторы демона не сделали это, чтобы SELinux знал и написал для него политику, тогда вы сами. Вы должны проанализировать, что делают ваши службы и как они взаимодействуют с SELinux, и выработать собственную политику, позволяющую это делать. Есть инструменты, которые помогут вам Audit2Why , Audit2allow и т. Д.

... Это единственный способ?

Нет, но это зависит от того, что вы пытаетесь сделать, и от того, как вы пытаетесь это сделать, в отношении решения. Например, вы можете привязать nginx (httpd_t) к порту 8010 (unreserved_port_t). Когда вы запускаете nginx, он терпит неудачу

Starting nginx: nginx: [emerg] bind() to 0.0.0.0:8010 failed (13: Permission denied)

и вы (в конце концов) загляните в журнал аудита и найдете

type=AVC msg=audit(1457904756.503:41673): avc:  denied  { name_bind } for
pid=30483 comm="nginx" src=8010 scontext=unconfined_u:system_r:httpd_t:s0
tcontext=system_u:object_r:port_t:s0 tclass=tcp_socket

Вы можете выполнить это через audit2alllow и наивно принять его выводы

allow httpd_t port_t:tcp_socket name_bind;

который затем позволяет httpd_t подключаться к любому порту TCP. Это может быть не то, что вы хотите.

Вы можете использовать sesearch, чтобы исследовать политику и посмотреть, к каким типам портов может подключиться httpd_t.

sesearch --allow -s httpd_t | grep name_bind
...
allow httpd_t http_port_t : tcp_socket name_bind ;
allow httpd_t http_port_t : udp_socket name_bind ;
...

Среди других типов http_t может связываться с http_port_t. Теперь вы можете использовать semanage, чтобы копать немного глубже.

semanage port -l | grep http_port_t
http_port_t                    tcp      80, 81, 443, 488, 8008, 8009, 8443, 9000
...

Порт 8010 не указан. Поскольку мы хотим, чтобы nginx связывался с портом 8010, добавление его в список http_port_t не является необоснованным.

semanage port -a -t http_port_t -p tcp 8010

Теперь nginx будет разрешено связывать name_bind с портом 8010, а не с каждым портом tcp, как указано выше.

Как вы точно знаете, что включено?

Изменения в политике довольно легко прочитать, выполняя ваши сообщения выше через audit2allow, мы получаем

allow httpd_t httpd_sys_content_t:sock_file write;
allow httpd_t initrc_t:unix_stream_socket connectto;

которые кажутся довольно очевидными.

Первый из них относится к файлу с inum 76151. Вы можете использовать find, чтобы получить его имя (find / -inum 76151), а затем использовать semanage fcontext -a -t ...для изменения политики и restorecon, чтобы исправить контекст.

Второе относится к тому, /run/gunicorn/socketчто опять имеет неправильный контекст. Используя sesearch, мы видим, что http_t может подключаться к unix_stream_sockets типа (среди прочего) http_t. Таким образом, мы можем изменить контекст, например,

semanage fcontext -a -t httpd_t "/run/gunicorn(/.*)?"
restorecon -r /run

Это устанавливает контекст / run / gunicorn и дерево | файлы ниже этого к httpd_t.

Как это должно работать, если вы настраиваете машины под автоматизацию?

Вам необходимо проанализировать систему и внести соответствующие изменения в тест. Затем вы используете свои средства автоматизации для развертывания изменений, puppet и ansible имеют поддержку для этого.

Конечно, вы можете делать все это в производственном процессе, когда SElinux настроен на разрешительную работу. Соберите все сообщения, проанализируйте их, определите ваши изменения и разверните их.

О SELinux можно узнать гораздо больше, но это предел моих навыков, Майкл Хэмптон лучше, а Мэтью Ифе снова намного лучше, возможно, им есть что добавить.

user9517
источник
1
Ваш совет является тщательным и помогает мне самому решить эти проблемы, хотя все еще оставляет меня немного в стороне. allow httpd_t httpd_sys_content_t:sock_file write;не так очевидно для меня, как вы надеялись. Что это говорит о том, что политика в этом файле должна быть изменена (то есть, что следует -tв semanageкоманде?
drs
Кроме того, я получаю инструкции по использованию при semanageнепосредственном использовании ваших команд. Мне нужно добавить --addаргумент.
DRS
На самом деле, я также должен сказать, что после изменения типа файла сокета на то, httpd_var_run_tчто Майкл Хэмптон отметил ниже, появляется audit2allowсообщение:allow httpd_t var_run_t:sock_file write;
drs
Похоже, вы установили его на var_run_tнет httpd_var_run_t.
user9517
@ Угу, хм .. без кубиков. Теперь audit2allowговоритallow httpd_t var_run_t:sock_file write;
DRS
2

Тип, который вы хотите использовать, не является httpd_sys_content_t. Это для статических файлов, которые веб-сервер предназначен для обслуживания пользовательских агентов.

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

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

Майкл Хэмптон
источник
3
Спасибо! Похоже, это решило одну из проблем SELinux. Любые указатели о том, как настроить gunicorn (или любой другой сервис) в ограниченном?
DRS
1

Я пробовал предыдущие ответы безуспешно, в моем случае я использую сервер nginx в качестве интерфейса для приложения uwsgi, использующего сокеты unix для их передачи, моя ОС Это сервер Fedora 26.

Unix сокеты создаются в каталоге /var/local/myapp:

/var/local/myapp/server.sock    
/var/local/myapp/stats.sock

Для настройки SELinux мне пришлось добавить тип контекста: httpd_sys_rw_content_t

semanage fcontext -at httpd_sys_rw_content_t "/var/local/myapp(/.*)?"
restorecon -R -v '/var/local/myapp' 
rsc1975
источник