SELinuxでNGINXおよびNGINX Plusを使用する

NGINX | 2018年8月17日

編集者注 – 「NGINX: RHEL 6.6 / CentOS 6.6へのアップグレード時のSELinuxの変更」というタイトルのブログ記事から、このページにリダイレクトされます。この記事では、更新された、より汎用的な情報を提供します。

最新のRed Hat Enterprise Linux(RHEL)および関連ディストリビューションにおけるSecurity-Enhanced Linux(SELinux)のデフォルト設定は、利便性よりもセキュリティを優先するため、非常に厳格な場合があります。デフォルト設定では、標準構成のNGINX Open SourceおよびNGINX Plusの動作は制限されませんが、追加で構成する機能については、SELinuxで明示的に許可しない限りブロックされる可能性があります。この記事では、発生する可能性のある問題と、推奨される解決方法について説明します。

[編集者注 – この記事はNGINX Open SourceとNGINX Plusの両方に適用されます。読みやすさを考慮し、全体を通して「NGINX」という用語を使用します。

CentOSは、もともとRHELから派生した関連ディストリビューションであり、NGINXおよびNGINX Plusでサポートされています。また、NGINX Plusは、関連するAmazon LinuxおよびOracle Linuxディストリビューションもサポートしています。これらのデフォルトのSELinux設定はCentOSやRHELと異なる場合があるため、ベンダーのドキュメントを参照してください。]

SELinuxの概要

最新のRHELおよびCentOSサーバーでは、SELinuxがデフォルトで有効になっています。オペレーティングシステムの各オブジェクト(プロセス、ファイルディスクリプター、ファイルなど)には、そのオブジェクトに許可される権限と操作を定義するSELinuxコンテキストが付与されます。RHEL 6.6/CentOS 6.6以降では、NGINXに「httpd_t」コンテキストが付与されます。

# ps auZ | grep nginxunconfined_u:system_r:httpd_t:s0 3234 ? Ss 0:00 nginx: master process /usr/sbin/nginx \
                                                -c /etc/nginx/nginx.conf
unconfined_u:system_r:httpd_t:s0 3236 ? Ss 0:00 nginx: worker process

The httpd_tコンテキストでは、NGINXが一般的なWebサーバーポートでリッスンし、/etc/nginx内の設定ファイル、および標準のドキュメントルート(/usr/share/nginx)内のコンテンツにアクセスできます。一方、アップストリームへのプロキシや、ソケットを介した他のプロセスとの通信など、その他の多くの操作は許可されません。

NGINX向けSELinuxの一時的な無効化

SELinuxの制限を一時的に無効にし、NGINXがSELinuxを使用しないOSと同じ操作をすべて実行できるようにするには、httpd_tコンテキストをhttpd_tコンテキストをpermissiveドメインに割り当てます。詳しくは次のセクションを参照してください。

# semanage permissive -a httpd_t

SELinuxモードの変更

SELinuxは、enforcing、permissive、またはdisabledの各モード(ドメインとも呼ばれます)で実行できます。デフォルトの厳格な権限に違反する可能性があるNGINXの設定変更を行う前に、テスト環境(利用可能な場合)または本番環境で、SELinuxをenforcingモードからpermissiveモードに変更できます。permissiveモードでは、SELinuxはすべての操作を許可しますが、enforcingモードでセキュリティポリシーに違反する操作をログに記録します。

To add httpd_tをpermissiveドメインのリストに追加するには、次のコマンドを実行します。

# semanage permissive -a httpd_t

To delete httpd_tをpermissiveドメインのリストから削除するには、次を実行します:

# semanage permissive -d httpd_t

モードをグローバルに「permissive」に設定するには、次を実行します。

# setenforce 0

モードをグローバルに「enforcing」に設定するには、次を実行します。

# setenforce 1

SELinuxセキュリティ例外の解決

In permissiveモードでは、セキュリティ例外がLinuxのデフォルトの監査ログである「/var/log/audit/audit.log」に記録されます。NGINXをenforcingモードで実行している場合にのみ問題が発生する場合は、permissiveモードで記録された例外を確認し、それらを許可するようにセキュリティポリシーを更新してください。

問題1:プロキシ接続が禁止されている

デフォルトでは、SELinuxの設定により、NGINXからリモートのHTTP、FastCGI、その他のサーバーへの接続は許可されていません。これは、次のような監査ログメッセージで確認できます。

type=AVC msg=audit(1415714880.156:29): avc:  denied  { name_connect } for  pid=1349 \
  comm="nginx" dest=8080 scontext=unconfined_u:system_r:httpd_t:s0 \
  tcontext=system_u:object_r:http_cache_port_t:s0 tclass=tcp_socket
type=SYSCALL msg=audit(1415714880.156:29): arch=c000003e syscall=42 success=no \
  exit=-115 a0=b \a1=16125f8 a2=10 a3=7fffc2bab440 items=0 ppid=1347 pid=1349 \
  auid=1000 uid=497 gid=496 euid=497 suid=497 fsuid=497 egid=496 sgid=496 fsgid=496 \
  tty=(none) ses=1 comm="nginx" exe="/usr/sbin/nginx" \
  subj=unconfined_u:system_r:httpd_t:s0 key=(null)

The audit2whyコマンドは、メッセージコード(1415714880.156:29)を解釈します:

# grep 1415714880.156:29 /var/log/audit/audit.log | audit2whytype=AVC msg=audit(1415714880.156:29): avc:  denied  { name_connect } for  pid=1349 \
  comm="nginx" dest=8080 scontext=unconfined_u:system_r:httpd_t:s0 \
  tcontext=system_u:object_r:http_cache_port_t:s0 tclass=tcp_socket
 
        Was caused by:
        One of the following booleans was set incorrectly.
        Description:
        Allow httpd to act as a relay
 
        Allow access by executing:
        # setsebool -P httpd_can_network_relay 1
        Description:
        Allow HTTPD scripts and modules to connect to the network using TCP.
 
        Allow access by executing:
        # setsebool -P httpd_can_network_connect 1

The output from audit2whyの出力は、httpd_can_network_relayとhttpd_can_network_connectの一方または両方のブール値オプションを有効にすることで、NGINXによるプロキシ接続を許可できることを示しています。これらは一時的または永続的に有効にできます。永続的に有効にするには、出力に示されているように‑Pフラグを追加します。

Booleanオプションについて

The sesearchコマンドを使用すると、ブール値オプションの詳細情報を確認できます。このコマンドは、setoolsパッケージ(yum install setools)をインストールすると利用できます。ここでは、httpd_can_network_relayおよびhttpd_can_network_connectオプションの出力を示します。

The httpd_can_network_relayブールオプション

以下は、sesearchコマンドでhttpd_can_network_relayオプションについて確認した出力です。

# sesearch -A -s httpd_t -b httpd_can_network_relayFound 10 semantic av rules:
   allow httpd_t gopher_port_t : tcp_socket name_connect ;
   allow httpd_t http_cache_client_packet_t : packet { send recv } ;
   allow httpd_t ftp_port_t : tcp_socket name_connect ;
   allow httpd_t ftp_client_packet_t : packet { send recv } ;
   allow httpd_t http_client_packet_t : packet { send recv } ;
   allow httpd_t squid_port_t : tcp_socket name_connect ;
   allow httpd_t http_cache_port_t : tcp_socket name_connect ;
   allow httpd_t http_port_t : tcp_socket name_connect ;
   allow httpd_t gopher_client_packet_t : packet { send recv } ;
   allow httpd_t memcache_port_t : tcp_socket name_connect ;

この出力は、httpd_can_network_relayにより、httpd_tコンテキストのラベルが付いたプロセス(NGINXなど)が、http_port_tタイプを含むさまざまなタイプのポートに接続できることを示しています:

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

許可されているポートのセットに追加のポート(ここでは8082)をhttp_port_t用として追加するには、次を実行します。

# semanage port -a -t http_port_t -p tcp 8082

このコマンドの出力に、次の例のようにポートが「already defined」と表示される場合、そのポートは別のセットに含まれています。他のサービスに悪影響を及ぼす可能性があるため、http_port_tに再割り当てしないでください。

# semanage port -a -t http_port_t -p tcp 8080
/usr/sbin/semanage: Port tcp/8080 already defined
# semanage port -l | grep 8080
http_cache_port_t              tcp      3128, 8080, 8118, 8123, 10001-10010

The httpd_can_network_connectブール値オプション

以下は、sesearchコマンドでhttpd_can_network_connectオプションについて確認した出力です。

# sesearch -A -s httpd_t -b httpd_can_network_connectFound 1 semantic av rules:
   allow httpd_t port_type : tcp_socket name_connect ;

この出力は、httpd_can_network_connectにより、httpd_tコンテキストのラベルが付いたプロセス(NGINXなど)が、port_type属性を持つすべてのTCPソケットタイプに接続できることを示しています。これらを一覧表示するには、次のコマンドを実行します。

# seinfo -aport_type -x

問題2:ファイルへのアクセスが禁止されている

デフォルトでは、SELinuxの設定により、NGINXは既知の許可された場所にないファイルにはアクセスできません。これは、次のような監査ログメッセージで確認できます。

type=AVC msg=audit(1415715270.766:31): avc:  denied  { getattr } for  pid=1380 \
  comm="nginx" path="/www/t.txt" dev=vda1 ino=1084 \
  scontext=unconfined_u:system_r:httpd_t:s0 \
  tcontext=unconfined_u:object_r:default_t:s0 tclass=file

The audit2whyコマンドは、メッセージコード(1415715270.766:31)を解釈します:

# grep 1415715270.766:31 /var/log/audit/audit.log | audit2whytype=AVC msg=audit(1415715270.766:31): avc:  denied  { getattr } for  pid=1380 \
  comm="nginx" path="/www/t.txt" dev=vda1 ino=1084 \
  scontext=unconfined_u:system_r:httpd_t:s0 \
  tcontext=unconfined_u:object_r:default_t:s0 tclass=file
 
    Was caused by:
        Missing type enforcement (TE) allow rule.
 
        You can use audit2allow to generate a loadable module to allow this access.

ファイルへのアクセスが禁止されている場合、2つの選択肢があります。

オプション1:ファイルラベルを変更する

NGINX(httpd_tコンテキストのラベルが付いたプロセス)がファイルにアクセスできるように、ファイルラベルを変更します:

# chcon -v --type=httpd_sys_content_t /www/t.txt

デフォルトでは、ファイルシステムのラベルを再設定すると、この変更は削除されます。変更を永続化するには、次のコマンドを実行します。

# semanage fcontext -a -t httpd_sys_content_t /www/t.txt
# restorecon -v /www/t.txt

複数のファイルのファイルラベルを変更するには、次のコマンドを実行します。

# semanage fcontext -a -t httpd_sys_content_t '/www(/.*)?'# restorecon -Rv /www

オプション2:httpd_tドメインの権限を拡張

追加のファイルの場所へのアクセスを許可するように、httpd_tのポリシーを拡張します:

# grep nginx /var/log/audit/audit.log | audit2allow -m nginx > nginx.te# cat nginx.te
 
module nginx 1.0;
 
require {
        type httpd_t;
        type default_t;
        type http_cache_port_t;
        class tcp_socket name_connect;
        class file { read getattr open };
}
 
#============= httpd_t ==============
allow httpd_t default_t:file { read getattr open };
 
#!!!! This avc can be allowed using one of these booleans:
#     httpd_can_network_relay, httpd_can_network_connect
allow httpd_t http_cache_port_t:tcp_socket name_connect;

コンパイル済みポリシーを生成するには、-Mオプションを指定します:

# grep nginx /var/log/audit/audit.log | audit2allow -M nginx

ポリシーを読み込むには、semodule -iを実行し、次にsemodule -lで正常に読み込まれたことを確認します:

# semodule -i nginx.pp
# semodule -l | grep nginx
nginx 1.0

この変更は再起動後も維持されます。

問題3:NGINXが追加のポートにバインドできない

デフォルトでは、SELinuxの設定により、NGINXはbind()を使用して、http_port_tタイプで許可リストに登録されているデフォルトのポート以外のTCPまたはUDPポートをリッスンできません。

# semanage port -l | grep http_port_thttp_port_t                    tcp      80, 443, 488, 8008, 8009, 8443

NGINXが許可リストにないポートでリッスンするように設定しようとすると(NGINX設定のlistenディレクティブをhttp、stream、またはmailコンテキストで使用した場合)、NGINX設定の検証(nginx -t)時または再読み込み時にエラーが発生します。次のNGINXログエントリは、このエラーを示しています。

YYYY/MM/DD hh:mm:ss [emerg] 46123#0: bind() to 0.0.0.0:8001 failed (13: Permission denied)

You can use semanageを使用して、目的のポート(ここでは8001)をhttp_port_tタイプに追加できます。

# semanage port -a -t http_port_t -p tcp 8001

新しい設定を反映するため、NGINXをリロードします。

# nginx -s reload

問題4:Too many files are openエラー

開いているファイル数の上限(RLIMIT_NOFILE)を超えると、エラーログに次のメッセージが表示されます。

Too many files are open

NGINXワーカープロセスでエラーが発生する場合

ほとんどの場合、このエラーはNGINXワーカープロセスによって報告されますが、NGINXの「worker_rlimit_nofile」ディレクティブを使用して上限を引き上げることはできません。これは、以下のエラーログおよび監査ログのメッセージに示されているように、SELinuxが「setrlimit()」システムコールを許可していないためです。

  • CentOS/RHEL 7.4以降の「/var/log/nginx/error.log」:
YYYY/MM/DD hh:mm:ss [alert] 12066#0: setrlimit(RLIMIT_NOFILE, 2342) failed (13: Permission denied)
  • CentOS/RHEL 8.0以降では、/var/log/nginx/error.logに記録されます:
YYYY/MM/DD hh:mm:ss [alert] 3327#0: setrlimit(RLIMIT_NOFILE, 65535) failed (1: Operation not permitted)
  • CentOS/RHEL 7.4以降では/var/log/audit/audit.log、CentOS/RHEL 8.0以降では/var/log/messagesに記録されます:
type=AVC msg=audit(1437731200.211:366): avc:  denied  { setrlimit } for pid=12066 \  comm="nginx" scontext=system_u:system_r:httpd_t:s0 \
  tcontext=system_u:system_r:httpd_t:s0 tclass=process

上限を引き上げるには、代わりにこのコマンドをrootユーザーとして実行します。

$ setsebool -P httpd_setrlimit 1

NGINXマスタープロセスでエラーが発生する場合

NGINXマスタープロセスでエラーが報告された場合は、NGINXのsystemd unitファイルを更新する必要があります。これにより、マスタープロセスとワーカープロセスの両方にファイルディスクリプターの上限が設定されます。

  1. Create a directory for the nginx.service設定用のディレクトリを作成します:
$ mkdir /etc/systemd/system/nginx.service.d
  1. 次の行を/etc/systemd/system/nginx.service.d/nofile_limit.confに追加します:
[Service]LimitNOFILE=65535
  1. systemdデーモンの設定を再読み込みし、NGINXを再起動します:
$ systemctl daemon-reload$ systemctl restart nginx.service

関連リソース

SELinuxは、オペレーティングシステムの権限を管理するための複雑かつ強力な機能です。詳細については、以下のドキュメントを参照してください。


共有
タグ: F5 NGINX, 2018, Tech

著者について

Owen Garrett
Owen Garrettプロダクトマネジメント担当シニアディレクター

Owen Garrettのその他のブログ記事

関連するブログ記事

チュートリアル:NGINXを使用してアプリケーション向けにOpenTelemetryを構成する
NGINX | 2024/01/18

チュートリアル:NGINXを使用してアプリケーション向けにOpenTelemetryを構成する

OpenTelemetryを使用してNGINXサーバーの状態と健全性をより明確に把握することで、問題のトラブルシューティングを行い、Webアプリケーションのパフォーマンスを向上できます。

AkitaのNGINX Plus認定モジュールでAPIエンドポイントの問題を特定・修正
NGINX | 2023/05/31

AkitaのNGINX Plus認定モジュールでAPIエンドポイントの問題を特定・修正

Akita SoftwareのAPIオブザーバビリティ向け新しいNGINX Plus Certified Moduleを活用して、APIエンドポイントの問題をより迅速に特定し、修正できます。

JavaプロジェクトをスキャフォールディングしてKubernetesネイティブアプリを構築する方法
NGINX | 2023/02/09

JavaプロジェクトをスキャフォールディングしてKubernetesネイティブアプリを構築する方法

Red HatのシニアプリンシパルデベロッパーアドボケイトであるDaniel Oh氏が、Javaプロジェクトをゼロから構築するためのひな形を作成し、Kubernetesネイティブアプリケーションとしてビルドする方法を解説します。

F5 NGINXaaS for Azureのご紹介:Microsoft Azureでネイティブに利用できるSaaS型ロードバランシング
NGINX | 2022/05/24

F5 NGINXaaS for Azureのご紹介:Microsoft Azureでネイティブに利用できるSaaS型ロードバランシング

NGINXaaS for Azureは、NGINX PlusをAzureネイティブのSaaSとして利用できるサービスです。NGINXの設定を容易にリフト&シフトできるため、クラウド導入とモダンアプリの展開を加速できます。

SELinuxでNGINXおよびNGINX Plusを使用する
NGINX | 2018/08/17

SELinuxでNGINXおよびNGINX Plusを使用する

Red Hat Enterprise Linux(RHEL)および関連ディストリビューションでSecurity-Enhanced Linux(SELinux)を有効にすると、デフォルト設定によりNGINXとNGINX Plusの一部の操作が制限されます。この記事では、すべての機能を利用できるようにSELinuxの設定を変更する方法について説明します。

NGINX PlusによるAWS Auto Scalingグループの負荷分散
NGINX | 2017/03/06

NGINX PlusによるAWS Auto Scalingグループの負荷分散

新しいnginx-asg-sync統合ソフトウェアにより、NGINX PlusはAWS Auto Scalingグループの負荷を直接分散できるため、クラウドでの負荷分散がさらに柔軟になります