Назад | Перейти на главную страницу

Подключение базы данных к postgresql отклонено для приложения flask под mod_wsgi при запуске с помощью systemd

У меня странная проблема с приложением фляги, которое я пытаюсь запустить (https://github.com/pyfarm/pyfarm-master) под mod_wsgi под Apache под CentOS 7 не может подключиться к локальному серверу postgresql - но только если указанный apache был запущен из systemd с помощью systemctl. Если я запустил apache вручную, используя /usr/sbin/httpd -DFOREGROUND в командной строке (та же команда systemd говорит, что ее использует) все работает нормально.

Apache, Postgresql и mod_wsgi практически не меняются при установке по умолчанию из репозитория CentOS или EPEL. Pyfarm-core и pyfarm-master были установлены с помощью pip.

Конфигурация postgresql не изменилась по сравнению с настройкой по умолчанию, за исключением установки аутентификации на основе хоста на "trust" для всего, что является localhost:

# "local" is for Unix domain socket connections only
local   all             all                                     trust
# IPv4 local connections:
host    all             all             127.0.0.1/32            trust
# IPv6 local connections:
host    all             all             ::1/128                 trust

После этого я создал пользователя и базу данных с

CREATE USER pyfarm WITH PASSWORD 'pyfarmpw';
CREATE DATABASE pyfarm WITH OWNER pyfarm;

Впоследствии я мог войти в базу данных pyfarm как пользователь pyfarm с помощью psql.

Apache также почти не изменился по сравнению с конфигурацией по умолчанию. Единственное, что я изменил, это добавить новый файл /etc/httpd/conf.d/pyfarm.conf со следующим содержанием:

<VirtualHost *>
  ServerName pyfarm.produktion.local
  ServerAlias pyfarm

  SetEnv PYFARM_APP_INSTANCE True
  SetEnv PYFARM_SECRET_KEY 2qgsd4hHaalvAn7
  SetEnv PYFARM_CONFIG Prod
  SetEnv PYFARM_DB_PREFIX ""
  SetEnv PYFARM_DATABASE_URI postgresql+psycopg2://pyfarm:pyfarmpw@127.0.0.1/pyfarm
  SetEnv TDB_DRIVER psycopg2 

  WSGIScriptAlias / /var/www/pyfarm/pyfarm.wsgi

  DocumentRoot /var/www/pyfarm

  <Directory /var/www/pyfarm>
      Order allow,deny
      Allow from all
  </Directory>
</VirtualHost>

(Пароли и секретные ключи в этих файлах конфигурации не очень важны и все равно будут изменены ...)

Этот файл ссылается на /var/www/pyfarm/pyfarm.wsgi, который выглядит так:

import os

def application(environ, start_response):
     for key in environ:
         if key.startswith("PYFARM_") or key.startswith("TDB_"):
             os.environ[key] = environ[key]

     from pyfarm.master.entrypoints import app as application_

     return application_(environ, start_response)

(Это должно быть так сложно, потому что в противном случае приложение не увидит переменные среды, установленные в apache.)

Доступ к любой странице из приложения, которая на самом деле не нуждается в базе данных, работает нормально после этих шагов, но как только я пытаюсь получить доступ к той, которая нужна, я получаю код возврата 500 и следующие ошибки в error_log Apache:

[Thu Jul 03 18:01:20.099007 2014] [:info] [pid 18094] mod_wsgi (pid=18094): Initializing Python.
[Thu Jul 03 18:01:20.106601 2014] [:info] [pid 18094] mod_wsgi (pid=18094): Attach interpreter ''.
[Thu Jul 03 18:01:20.116951 2014] [:error] [pid 18080] \x1b[31m2014-07-03 18:01:20 ERROR    - pyfarm.master   - Exception on /api/v1/agents/ [GET]
[Thu Jul 03 18:01:20.116964 2014] [:error] [pid 18080] Traceback (most recent call last):
[Thu Jul 03 18:01:20.116968 2014] [:error] [pid 18080]   File "/usr/lib/python2.7/site-packages/flask/app.py", line 1817, in wsgi_app
[Thu Jul 03 18:01:20.116971 2014] [:error] [pid 18080]     response = self.full_dispatch_request()
[Thu Jul 03 18:01:20.116974 2014] [:error] [pid 18080]   File "/usr/lib/python2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request
[Thu Jul 03 18:01:20.116977 2014] [:error] [pid 18080]     rv = self.handle_user_exception(e)
[Thu Jul 03 18:01:20.116989 2014] [:error] [pid 18080]   File "/usr/lib/python2.7/site-packages/flask/app.py", line 1381, in handle_user_exception
[Thu Jul 03 18:01:20.116993 2014] [:error] [pid 18080]     reraise(exc_type, exc_value, tb)
[Thu Jul 03 18:01:20.116996 2014] [:error] [pid 18080]   File "/usr/lib/python2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request
[Thu Jul 03 18:01:20.116999 2014] [:error] [pid 18080]     rv = self.dispatch_request()
[Thu Jul 03 18:01:20.117001 2014] [:error] [pid 18080]   File "/usr/lib/python2.7/site-packages/flask/app.py", line 1461, in dispatch_request
[Thu Jul 03 18:01:20.117005 2014] [:error] [pid 18080]     return self.view_functions[rule.endpoint](**req.view_args)
[Thu Jul 03 18:01:20.117007 2014] [:error] [pid 18080]   File "/usr/lib/python2.7/site-packages/flask/views.py", line 84, in view
[Thu Jul 03 18:01:20.117010 2014] [:error] [pid 18080]     return self.dispatch_request(*args, **kwargs)
[Thu Jul 03 18:01:20.117013 2014] [:error] [pid 18080]   File "/usr/lib/python2.7/site-packages/flask/views.py", line 149, in dispatch_request
[Thu Jul 03 18:01:20.117016 2014] [:error] [pid 18080]     return meth(*args, **kwargs)
[Thu Jul 03 18:01:20.117019 2014] [:error] [pid 18080]   File "/usr/lib/python2.7/site-packages/pyfarm/master/api/agents.py", line 412, in get
[Thu Jul 03 18:01:20.117021 2014] [:error] [pid 18080]     for host in query:
[Thu Jul 03 18:01:20.117024 2014] [:error] [pid 18080]   File "/usr/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 2405, in __iter__
[Thu Jul 03 18:01:20.117027 2014] [:error] [pid 18080]     return self._execute_and_instances(context)
[Thu Jul 03 18:01:20.117030 2014] [:error] [pid 18080]   File "/usr/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 2418, in _execute_and_instances
[Thu Jul 03 18:01:20.117033 2014] [:error] [pid 18080]     close_with_result=True)
[Thu Jul 03 18:01:20.117037 2014] [:error] [pid 18080]   File "/usr/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 2409, in _connection_from_session
[Thu Jul 03 18:01:20.117040 2014] [:error] [pid 18080]     **kw)
[Thu Jul 03 18:01:20.117043 2014] [:error] [pid 18080]   File "/usr/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 846, in connection
[Thu Jul 03 18:01:20.117046 2014] [:error] [pid 18080]     close_with_result=close_with_result)
[Thu Jul 03 18:01:20.117048 2014] [:error] [pid 18080]   File "/usr/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 850, in _connection_for_bind
[Thu Jul 03 18:01:20.117051 2014] [:error] [pid 18080]     return self.transaction._connection_for_bind(engine)
[Thu Jul 03 18:01:20.117054 2014] [:error] [pid 18080]   File "/usr/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 315, in _connection_for_bind
[Thu Jul 03 18:01:20.117057 2014] [:error] [pid 18080]     conn = bind.contextual_connect()
[Thu Jul 03 18:01:20.117060 2014] [:error] [pid 18080]   File "/usr/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1737, in contextual_connect
[Thu Jul 03 18:01:20.117063 2014] [:error] [pid 18080]     self.pool.connect(),
[Thu Jul 03 18:01:20.117065 2014] [:error] [pid 18080]   File "/usr/lib/python2.7/site-packages/sqlalchemy/pool.py", line 332, in connect
[Thu Jul 03 18:01:20.117068 2014] [:error] [pid 18080]     return _ConnectionFairy._checkout(self)
[Thu Jul 03 18:01:20.117071 2014] [:error] [pid 18080]   File "/usr/lib/python2.7/site-packages/sqlalchemy/pool.py", line 630, in _checkout
[Thu Jul 03 18:01:20.117074 2014] [:error] [pid 18080]     fairy = _ConnectionRecord.checkout(pool)
[Thu Jul 03 18:01:20.117076 2014] [:error] [pid 18080]   File "/usr/lib/python2.7/site-packages/sqlalchemy/pool.py", line 433, in checkout
[Thu Jul 03 18:01:20.117079 2014] [:error] [pid 18080]     rec = pool._do_get()
[Thu Jul 03 18:01:20.117082 2014] [:error] [pid 18080]   File "/usr/lib/python2.7/site-packages/sqlalchemy/pool.py", line 949, in _do_get
[Thu Jul 03 18:01:20.117085 2014] [:error] [pid 18080]     return self._create_connection()
[Thu Jul 03 18:01:20.117091 2014] [:error] [pid 18080]   File "/usr/lib/python2.7/site-packages/sqlalchemy/pool.py", line 278, in _create_connection
[Thu Jul 03 18:01:20.117094 2014] [:error] [pid 18080]     return _ConnectionRecord(self)
[Thu Jul 03 18:01:20.117097 2014] [:error] [pid 18080]   File "/usr/lib/python2.7/site-packages/sqlalchemy/pool.py", line 404, in __init__
[Thu Jul 03 18:01:20.117099 2014] [:error] [pid 18080]     self.connection = self.__connect()
[Thu Jul 03 18:01:20.117102 2014] [:error] [pid 18080]   File "/usr/lib/python2.7/site-packages/sqlalchemy/pool.py", line 530, in __connect
[Thu Jul 03 18:01:20.117105 2014] [:error] [pid 18080]     connection = self.__pool._creator()
[Thu Jul 03 18:01:20.117108 2014] [:error] [pid 18080]   File "/usr/lib/python2.7/site-packages/sqlalchemy/engine/strategies.py", line 95, in connect
[Thu Jul 03 18:01:20.117111 2014] [:error] [pid 18080]     connection_invalidated=invalidated
[Thu Jul 03 18:01:20.117113 2014] [:error] [pid 18080]   File "/usr/lib/python2.7/site-packages/sqlalchemy/util/compat.py", line 189, in raise_from_cause
[Thu Jul 03 18:01:20.117116 2014] [:error] [pid 18080]     reraise(type(exception), exception, tb=exc_tb)
[Thu Jul 03 18:01:20.117119 2014] [:error] [pid 18080]   File "/usr/lib/python2.7/site-packages/sqlalchemy/engine/strategies.py", line 89, in connect
[Thu Jul 03 18:01:20.117122 2014] [:error] [pid 18080]     return dialect.connect(*cargs, **cparams)
[Thu Jul 03 18:01:20.117125 2014] [:error] [pid 18080]   File "/usr/lib/python2.7/site-packages/sqlalchemy/engine/default.py", line 376, in connect
[Thu Jul 03 18:01:20.117127 2014] [:error] [pid 18080]     return self.dbapi.connect(*cargs, **cparams)
[Thu Jul 03 18:01:20.117130 2014] [:error] [pid 18080]   File "/usr/lib64/python2.7/site-packages/psycopg2/__init__.py", line 164, in connect
[Thu Jul 03 18:01:20.117133 2014] [:error] [pid 18080]     conn = _connect(dsn, connection_factory=connection_factory, async=async)
[Thu Jul 03 18:01:20.117136 2014] [:error] [pid 18080] OperationalError: (OperationalError) could not connect to server: Permission denied
[Thu Jul 03 18:01:20.117138 2014] [:error] [pid 18080] \tIs the server running on host "127.0.0.1" and accepting
[Thu Jul 03 18:01:20.117141 2014] [:error] [pid 18080] \tTCP/IP connections on port 5432?
[Thu Jul 03 18:01:20.117144 2014] [:error] [pid 18080]  None None\x1b[39m

Однако, когда я останавливаю apache с помощью systemctl stop httpd.service и перезапустите его снова с помощью /usr/sbin/httpd -DFOREGROUND, все работает нормально, включая страницы, требующие доступа к базе данных.

Когда Apache работает таким образом, я вижу, как приложение создает и использует соединение с базой данных в tcpdump -i lo. Когда Apache запускается из systemd, в tcpdump не видны такие соединения, даже SYN-пакет.

Очевидно, что запуск Apache вручную каждый раз не является долгосрочным решением. Кто-нибудь знает, что здесь происходит не так? Может быть, какое-то ограничение возможностей, специфичное для systemd, не позволяет какой-либо службе устанавливать исходящие TCP-соединения?

Когда у вас включен SELinux, веб-серверу (и процессам, которые выполняются внутри него, например, mod_wsgi, а на EL 7, на аналогичных серверных процессах, запускаемых даже отдельно от веб-сервера) не разрешается устанавливать исходящие сетевые подключения, если вы явно не позвольте им сделать это, например используя логическое значение SELinux.

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

setsebool -P httpd_can_network_connect_db 1