RedHatでPHPからDBサーバに接続できないときはSELinuxの設定が原因かも?
数年ぶりにRedHat系OS(Amazon Linuxは除く)を使い、記憶の彼方に消えていた SELinux と再会する機会があったので、メモを残しておきます。
事象
RedHat 7.5 + Apache/PHP + AWS RDS(MySQL)というよくある構成で、PHP から RDS MySQL に接続できないという現象に出くわしました。
RedHat サーバーからは
- MySQL CLI
- コマンドラインの PHP
ともにリモートの MySQL に接続できますが、Apache 上で動作する PHP プログラムからは MySQL へ接続できませんでした。
Warning: mysqli_real_connect(): (HY000/2003): Can't connect to MySQL server on 'foo.bar.eu-central-1.rds.amazonaws.com' (13) in /var/www/html/wordpress/wp-includes/wp-db.php on line 1531
原因
RedHat 7.5ではデフォルトで SELinux が有効になっています。
特に、Apacheプロセスで動作するHTTPスクリプト・モジュールから外部への通信(httpd_can_network_connect
)が無効化(off
)されています。
# SELinux のステータス $ getenforce Enforcing $ getsebool httpd_can_network_connect httpd_can_network_connect --> off
このような設定になっているために PHP からリモートで動作する MySQL サーバへ接続できませんでした。
対応
対応としては
- SELinux を無効化
- 外部通信全般を許可(
$ sudo setsebool -P httpd_can_network_connect=1
) - 主要データベース向けポートへの通信だけを許可(#2 のサブセット)(
$ sudo setsebool -P httpd_can_network_connect_db=1
)
などがあります。
SELinux の機構を残したままの対応としては、後ろ二つが有力です。
なお setsebool
の -P
オプションは設定変更を永続化(permanent)させるものです。
似ている 2つの boolean の違いはなに?
今回登場した名前が似通った2つの boolean
- httpd_can_network_connect
- httpd_can_network_connect_db
の違いを確認します。
sesearch
を利用するため、このプログラムが存在しない場合、$ sudo yum install -y setools-console
でインストールします。
まず httpd_can_network_connect_db
の Access Vector(AV) ルールを確認します。
$ sesearch -A -s httpd_t -b httpd_can_network_connect_db -p name_connect Found 6 semantic av rules: allow httpd_t mongod_port_t : tcp_socket name_connect ; allow httpd_t gds_db_port_t : tcp_socket name_connect ; allow httpd_t mssql_port_t : tcp_socket name_connect ; allow httpd_t oracle_port_t : tcp_socket name_connect ; allow httpd_t postgresql_port_t : tcp_socket name_connect ; allow httpd_t mysqld_port_t : tcp_socket name_connect ;
主要データベースの名前が並んでいます。
これらのデータベースに接続するために許可されているポート一覧を確認してみましょう。
$ seinfo --protocol=tcp --port | grep -E 'mongod_port_t|gds_db_port_t|mssql_port_t|oracle_port_t|postgresql_port_t|mysqld_port_t' portcon tcp 1186 system_u:object_r:mysqld_port_t:s0 portcon tcp 1521 system_u:object_r:oracle_port_t:s0 portcon tcp 2483 system_u:object_r:oracle_port_t:s0 portcon tcp 2484 system_u:object_r:oracle_port_t:s0 portcon tcp 3050 system_u:object_r:gds_db_port_t:s0 portcon tcp 3306 system_u:object_r:mysqld_port_t:s0 portcon tcp 5432 system_u:object_r:postgresql_port_t:s0 portcon tcp 9898 system_u:object_r:postgresql_port_t:s0 portcon tcp 1433-1434 system_u:object_r:mssql_port_t:s0 portcon tcp 27017-27019 system_u:object_r:mongod_port_t:s0 portcon tcp 28017-28019 system_u:object_r:mongod_port_t:s0 portcon tcp 63132-63164 system_u:object_r:mysqld_port_t:s0
たとえば MySQL はデフォルトポートの 3306、PostgreSQL はデフォルトポートの 5432 だけでなく、pgpool-II 用の 9898 ポートも許可されていることがわかります。
一方で、システムが様々なデータストアを利用している場合、httpd_can_network_connect_db
だけでは許可しきれない可能性が高まります。
そのようなケースでは、より汎用的な httpd_can_network_connect
を許可しましょう。