У меня есть запросы на пересылку 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.
Кажется смешным, что вы не можете настроить политику, позволяющую 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 может использовать name_bind для
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
который снова имеет неправильный контекст. Используя поиск, мы видим, что http_t может подключаться к unix_stream_sockets типа (среди прочего) http_t. Таким образом, мы можем соответственно изменить контекст, например
semanage fcontext -a -t httpd_t "/run/gunicorn(/.*)?"
restorecon -r /run
Это устанавливает контекст / run / gunicorn и дерева | файлы под ним в httpd_t.
Как это должно работать, если вы настраиваете машины в автоматическом режиме?
Вам необходимо проанализировать систему и внести соответствующие изменения в тест. Затем вы используете свои инструменты автоматизации для развертывания изменений, марионетка и доступный объект имеют для этого поддержку.
Конечно, вы можете делать все это в продакшене с SElinux, установленным на permissive. Соберите все сообщения, проанализируйте их, выберите свои изменения и разверните их.
О SELinux нужно знать гораздо больше, но это предел моих навыков, Майкл Хэмптон лучше, а Мэтью Ифе снова намного лучше, им, возможно, есть что добавить.
Тип, который вы хотите использовать, не httpd_sys_content_t
. Это статические файлы, которые веб-сервер предназначен для обслуживания пользовательских агентов.
Для сокета, используемого для межпроцессного взаимодействия, вам нужен тип httpd_var_run_t
.
Однако учтите, что, поскольку вы запустили gunicorn без ограничений, могут возникнуть дополнительные проблемы при общении с ним.
Я безуспешно пробовал предыдущие ответы, в моем случае я использую сервер nginx в качестве интерфейса для приложения uwsgi, используя сокеты unix для их связи, мой O.S. Это сервер 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'