アクセス制限
【連載コラム:Linuxでサーバーを構築してみよう(7)】
考え方の1つに「基本は拒否。必要なものを明示的に許可する」という考え方がありますが、それはなぜでしょうか?
サーバー構築の連載コラムの7回目の今回は、アクセス制限について解説していきます。
目次
アクセス制限の基本的な考え方
サーバーはすべてのアクセスをすべてそのまま受け入れる、という考え方は、セキュリティ上取るべきではありません。「Webページは誰でも見るじゃないか」と思うかもしれませんが、サーバーはWebサーバーの機能だけを持っているというわけではないことに注意してください。
WordPressを利用する場合であればデータベースを扱いますし、ネットワーク経由でサーバー管理を行う際にSSHを利用することはよくあることです。SSHは実際に運用してみると、侵入経路の入り口としてよく狙われるポイントになるので、注意が必要です。
アクセス制限をどのように決めるかということもサーバー構築にあたっては重要なポイントの1つになります。アクセス制限は「これが正解!」と言えるものは状況によってまちまちなので、自分で考える必要が生じてきます。また、設定してみてはじめてアクセス制限の考え方を変える必要があることに気づくということもあります。
テスト環境を構築してあれば、テスト環境で実際にアクセス制限を設定することで、アクセス制限のポリシーを固めることができます。
基本は必要なものだけ許可
アクセス制限の考え方の1つに、「基本的にはアクセスを拒否する。そして必要なものだけを明示的に許可する」というものがあります。逆の「基本的には許可し、適宜拒否する」という考え方では、どうしても穴が随所にできてしまうためです。この考え方に則って、実際に設定を行う前にアクセス制限のポリシーを決めます。
たとえば「HTTPSの通信はすべてのアクセスを許可する」「SSHの通信は特定のIPアドレスからのみアクセスを許可する」などです。必要があればデータベースサーバとのやりとりも許可することになります。また、自ホストへのループバックをアクセス制限を拒否すると不具合が生じることが多々あるので許可します。
ICMPのパケットは、システム管理の利便性を考えて許可するという考え方と、ICMPパケットも攻撃に悪用される恐れがあるので拒否するという考え方がありますが、ここでは前者で考えます。
パケットフィルタリング
外部からのアクセス制限を利用するには、パケットフィルタリングを利用します。
パケットフィルタリングは、パケットの宛先ポートやIPアドレスなどに応じてパケットの受け取りを許可したり拒否したりする仕組みです。
Linuxではパケットフィルタリングの設定に以前はiptablesコマンドを利用していましたが、最近ではnftコマンド(パッケージ名は「nftables」)を利用するようになりました。nftablesはLinuxカーネルが直接フィルタリングを行うため、高速かつ安全性、信頼性の高いフィルタリングが可能です。
nftコマンドとパケットフィルタリングの設定の流れ
nftコマンドを利用してパケットフィルタリングを行う1つの例を次に示します。ただしこれはあくまで一例であって、この通りに設定を行えば完璧というものではないことに注意してください。
まずテーブルを定義します。ここでは「TABLE01」というテーブルを作成します。
# nft table ip TABLE01
そのテーブルにチェインというものを定義します。チェインというのはアクセス制御を行うルールを設定する場所です。ここでは、「INPUT01」というチェインを定義します。
# nft add chain ip TABLE01 INPUT01 { type filter hook input priority filter\; policy accept\;}
次に「明示的に許可するアクセス」をチェインに設定します。
# nft add rule TABLE01 INPUT01 ct state related,established accept ←接続成立後のパケットは許可
# nft add rule TABLE01 INPUT01 icmp type { echo-request, echo-reply } accept ←pingの応答に関するパケットは許可
# nft add rule TABLE01 INPUT01 iifname "lo" accept ←ループバック(自ホスト)のアクセスは許可
# nft add rule TABLE01 INPUT01 tcp dport 443 ct state new accept ←443番ポート(HTTPS)へのアクセスは許可
# nft add rule TABLE01 INPUT01 ip saddr XX.XX.XX.XX tcp dport 22 ct state new accept ←22番ポート(SSH)へのアクセスはIPアドレス XX.XX.XX.XXからのアクセスに限り許可
# nft add rule TABLE01 INPUT01 reject ←その他はアクセスを拒否
チェインは上から順番に評価されます。このため、明示的に許可していないアクセス以外は最後の「reject」によって拒否されることになります。この順序を誤ると、アクセス設定の途中でまったくアクセスができなくなってしまうケースがあるためです。よくあるミスの中に、リモートからパケットフィルタリングの設定を誤ったせいで、リモートからアクセスができなくなってしまうということがあります。十分注意してください。
設定の確認は以下のコマンドで行います。
# nft -a list chain ip TABLE01 INPUT01
設定を行ったら、たとえばWebサーバに対して(テストページでもよいので)アクセスができるか、指定したアドレス以外からSSHでの接続が拒否されるか、などをチェックします。
設定の保存とブート時の設定
現在かかっているパケットフィルタリングの設定を保存するためには以下のコマンドを実行します。
# nft list ruleset > /etc/sysconfig/nftables.conf
ディストリビューションによっては、nftablesというサービスを利用することによって、OS起動時に/etc/sysconfig/nftables.confの内容が読み込まれてシステムに反映されます。
# systemctl enable nftables.service
# systemctl start nftables.service
パケットフィルタリングの設定には、他にも色々なものがあります。是非、さまざまなものを試してみてください。
SELinuxで内部のアクセス制御を行う
サーバーの内部でのアクセス制御を行うには、SELinuxを利用します。SELinuxを利用すると、アクセス制限を細かく設定することが可能になります。SELinuxの強力な点は、root権限に制限をかけることも可能になっている点です。これを「強制アクセス制御 (MAC: Mandatory Access Control)」と呼びます。
SELinuxは、万が一侵入を許してしまった際に有効になるアクセス制限であり、侵入そのものを食い止めるものではないことに注意してください。
SELinuxの有効・無効化とpermissiveモード
SELinuxの状態を確認するには「getenforce」コマンドを利用します。
# genenforce
Enforcing
SELinuxの状態は3つあり、enforcingが「有効」、disabledが「無効」で、その他に「permissive」があります。
「permissive」モードは、アクセス制限そのものは有効にならないが、設定した制限に違反した場合にその旨がログに書き出されるというものです。SELinuxに慣れていない場合は、「permissive」モードを使って設定を行い、ログを参照して意図した制限がかけられているか否かをチェックするという手法がおすすめです。
SELinuxの設定の切り替え
SELinuxのEnforcingとpermissiveを切り替えるためには「setenforce」コマンドを利用します。
# setenforce permissive
SELinuxの有効化・無効化の設定は/etc/selinux/configファイルに行います。この中に、
SELINUX = enforcing
と記述すると有効に、「enforcing」を「disabled」にすると無効になります。なお設定の変更の反映はシステムを再起動することで行われます。
コンテキスト
SELinuxは、アクセスする側を「サブジェクト」、アクセスされる側を「オブジェクト」と呼びます。SELinuxでは、プロセスやファイルなどに「コンテキスト」と呼ばれるラベルを追加し、このコンテキストを「比較」することによってアクセス制御を行います。アクセスの可否を定義するルールは「ポリシー」と呼びます。
コンテキストは、以下のような書式で表されます。
ユーザ:ロール:タイプ:MLSレベル
コンテキストの確認
コンテキストを確認するには、lsコマンドやpsコマンドに「-Z」オプションをつけて実行します。
# ls -lZ /var/www
drwxr-xr-x. root root system_u:object_r:httpd_sys_script_exec_t:s0 cgi-bin
drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 error
drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 html
drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 icon
/var/www/html ディレクトリには、「httpd_sys_content_t」というタイプがついていることがわかります。名前から推測できる通り、httpdプロセスのアクセスに関わるコンテキストになっています。
コンテキストの付加
タイプを設定するには、chconコマンドを利用します。以下の例では、/var/www/tmpというディレクトリに対してhttpd_sys_content_tというコンテキストタイプを付加しています。
# chcon -t httpd_sys_content_t /var/www/tmp
これにポリシーの設定を行うことで適切なサブジェクト(ここではhttpdプロセス)のみアクセスを許可し、たとえrootユーザといえど容易にファイルやプロセスにアクセスできないようにすることで、システムを侵入者から守ります。
SELinuxは通常のユーザーやグループ、読み込みや書き込み、実行などとは大きく異なる方法でアクセス制限を行うため、設定が難しいからと敬遠されがちです。しかし、セキュリティを高めるためにはきちんと設定が必要です。
ここではSELinuxの概略しか説明できませんでしたが、より実践的なSELinuxの解説は『Linuxシステム管理標準教科書』の4章で解説しています。是非併せて確認してみてください。
https://linuc.org/textbooks/admin/
- 筆者紹介
川原 龍人 氏
1975年生まれ。 著書に「BIND9によるDNSサーバ構築」、「シェルスクリプト ポケットリファレンス Bash編(技術評論社)」など。 予備校講師としても活躍中。Linuxとのつきあいは20年を超える。
バックナンバー
第14回:バックアップ
第13回:異常発生時の対応
第12回:サーバー構築という仕事
第11回:ユーザー教育の重要性
第10回:テスト環境を構築する
第9回:ログローテーションとは
第8回:ログの取得と管理
第7回:アクセス制限
第6回:OpenSSHの活用
第5回:ユーザーアカウントとアクセス制限
第4回:テスト環境を構築する
第1回:Linuxでサーバーを構築しよう