ホストのセキュリティ設定

「ホストのセキュリティ設定」という主題は、1台のLinuxサーバー(ホスト)が持つ攻撃対象範囲(アタックサーフェス)を、基本的なところから小さくしていくための3つの観点をまとめたものです。

  • パスワードの保護:ログインに使うパスワード情報を、どう安全に保管するか(シャドウパスワード)。
  • 不要なサービスの停止:使っていないネットワークサービスを稼働させたままにしない。
  • ネットワークアクセスの制限:接続してよい相手を、TCPラッパーやファイアウォールでどう絞り込むか。

いずれも「難しい暗号技術を使う」というより、「余計なものを動かさない・見せない・繋がせない」という、地味だが基本的なセキュリティ対策の考え方です。

PAM(Pluggable Authentication Modules)とは

PAM(Pluggable Authentication Modules)は、LinuxをはじめとするUNIX系OSで、アプリケーションから認証処理を分離し、共通化するための仕組みです。ログイン、sudo、su、SSHなどのPAM対応アプリケーションは、認証方式を個別に実装する代わりにPAMを呼び出します。

これにより、パスワード認証、アカウントの有効期限確認、多要素認証、アクセス制限、セッション開始時の処理などを、アプリケーションを変更せずに追加・変更できます。

PAMの基本構成

PAMは主に次の要素で構成されます。

  • PAM対応アプリケーション

login、sshd、sudo、suなど、PAMを利用して認証処理を行うプログラム

  • PAMライブラリ

アプリケーションと各PAMモジュールを仲介する共通インターフェース

  • PAMモジュール

パスワード確認やアクセス制限など、個別の処理を実装する共有ライブラリ

  • PAM設定ファイル

サービスごとに、使用するモジュールと実行順序を定義するファイル

一般的なLinux環境では、設定ファイルは次の場所にあります。

/etc/pam.d/

たとえば、sudo用の設定は /etc/pam.d/sudo、SSH用の設定は通常 /etc/pam.d/sshd に記述されます。システムによっては /etc/pam.conf が使用される場合もあります。

シャドウパスワードのしくみ

/etc/passwd:ユーザー情報の一覧(誰でも読める)

/etc/passwdは、システムに登録されているユーザーアカウントの基本情報(ユーザー名、UID、GID、ホームディレクトリ、ログインシェルなど)を保存するファイルです。多くのコマンドがユーザー名とUIDの対応関係を調べるために参照するため、このファイルは一般ユーザーでも読み取れるパーミッション(多くの環境で644)になっています。

現在の一般的なLinuxシステムでは、/etc/passwdのパスワード欄(本来パスワードのハッシュ値が入る欄)にはxという文字が入っており、実際のパスワードハッシュはここには保存されていません。

/etc/shadow:パスワードハッシュの保管(rootのみ読める)

実際のパスワードのハッシュ値は、/etc/shadowという別ファイルに保存されています。/etc/shadowはroot(および一部の特権を持つグループ)以外は読み取れないパーミッション(多くの環境で600または640)になっており、一般ユーザーが他人のパスワードハッシュを読み取って解析することを防ぎます。

/etc/passwdを全ユーザーが読める状態に保ったまま、パスワードハッシュだけを別ファイルに分離して保護する、というこの2ファイルへの分離こそが「シャドウパスワード」という仕組みの本質です。/etc/shadowには、パスワードハッシュ以外にも、次のようなパスワードエージング(有効期限管理)に関する情報が保存されています。

  • 最後にパスワードを変更した日
  • 変更後、次にパスワードを変更できるまでの最短日数
  • パスワードの最長有効日数
  • 有効期限切れが近いことを警告し始める日数
  • 有効期限切れ後、アカウントが無効になるまでの猶予日数
  • アカウント自体の有効期限(アカウント無効化日)

/etc/nologin:ログインを一時的に禁止するファイル

/etc/nologinは、通常はPAMのpam_nologinを設定したログインサービスにおいて、このファイルが存在するかどうかでログインの可否を制御する、少し変わった仕組みのファイルです。

画像
  • pam_nologinを利用するログインサービスでは、/etc/nologinが存在すると、通常はroot以外のユーザーのログインが拒否されます。
  • ファイルの中身にメッセージを書いておくと、ログインを拒否された際にそのメッセージが表示されます。
  • 主にシステムメンテナンス作業中に、一時的に一般ユーザーのログインを禁止する目的で使われます。作業が終わればファイルを削除するだけで、pam_nologinを利用するログインサービスでは通常どおりログインできる状態に戻せます。

/etc/nologinと名前が似ているものに、/sbin/nologin(ディストリビューションによっては/usr/sbin/nologin)というシェルがありますが、これは全く別の仕組みです。

/etc/nologin(ファイル)/sbin/nologin(シェル)
正体ファイルの有無を確認する仕組みユーザーのログインシェルとして/etc/passwdに設定する実行ファイル
影響範囲pam_nologinを利用するログインサービスでは、通常はrootを除くユーザーログインシェルにこれを設定した特定のユーザーのみ
主な用途システムメンテナンス中の一時的なログイン禁止サービス用アカウント等、対話的なログインをさせたくないアカウントの恒常的な制限
解除方法ファイルを削除するログインシェルを別のシェルに変更する

/sbin/nologinをログインシェルに設定されたアカウントでログインを試みると、接続直後に切断されます(メッセージが表示される場合もあります)。ただし、これはあくまで対話的なシェルへのログインを拒否する仕組みであり、シェルを必要としない一部のサービス(例えばシェルを経由しない認証方式のサービス)経由でのアクセスまで一律に防げるとは限らない点に注意が必要です具体的にどのサービスがシェルを経由せずに動作するかは、そのサービス自体の実装に依存します。「ログインシェルをnologinにすれば、そのアカウントに関するアクセスを完全に遮断できる」という単純化はできません。[1]。

不要なネットワークサービスの無効化

Linuxサーバーで稼働するネットワークサービスが多いほど、外部から攻撃を受ける可能性のある入口(アタックサーフェス)が広がります。そのため、利用していないサービスは停止し、システム起動時にも自動起動しないように設定することが重要です。

作業前には、SSHなど現在のリモート接続に必要なサービスを誤って停止しないよう注意してください。

稼働中のネットワークサービスを確認する

不要なサービスを無効化する前に、待ち受け中のTCP・UDPポートを確認します。

ss -lntup

主なオプションは次のとおりです。

オプション説明
-l待ち受け状態のソケットを表示する
-nポート番号やIPアドレスを名前に変換せず、数値で表示する
-tTCPソケットを表示する
-uUDPソケットを表示する
-pソケットを使用しているプロセスを表示する

従来のnetstatコマンドでも確認できます。

netstat -lntup

プロセス名やPIDをすべて表示するには、root権限が必要な場合があります。


スーパーサーバーによるサービス管理

inetd

inetdは、複数のネットワークポートをまとめて監視し、接続要求があったときだけ対応するサーバープログラムを起動するスーパーサーバーです。

主な設定ファイルは次のものです。

/etc/inetd.conf

設定例は次のとおりです。

telnet  stream  tcp  nowait  root  /usr/sbin/tcpd  in.telnetd

サービスを無効化するには、対象行の先頭に#を付けてコメントアウトします。

#telnet  stream  tcp  nowait  root  /usr/sbin/tcpd  in.telnetd

設定変更後は、inetdに設定を再読み込みさせます。サービス名はディストリビューションによってinetdやopenbsd-inetdなど異なる場合があります。

service inetd reload

または、systemd環境では次のように実行します。

systemctl reload inetd.service

reloadに対応していない場合は再起動します。

service inetd restart

xinetd

xinetd(拡張インターネットサービスデーモン)は、inetdを拡張したスーパーサーバーです。アクセス制御や接続数の制限、ログ記録など、inetdより多くの機能を備えています。

主な設定ファイルは次のとおりです。

パス説明
/etc/xinetd.confxinetd全体の設定ファイル
/etc/xinetd.d/サービスごとの設定ファイルを格納するディレクトリ

たとえば、/etc/xinetd.d/telnetが次のように設定されているとします。

service telnet
{
    socket_type = stream
    protocol    = tcp
    wait        = no
    user        = root
    server      = /usr/sbin/in.telnetd
    disable     = no
}

このサービスを無効化するには、disableをyesに変更します。

service telnet
{
    socket_type = stream
    protocol    = tcp
    wait        = no
    user        = root
    server      = /usr/sbin/in.telnetd
    disable     = yes
}

設定変更後はxinetdに設定を再読み込みさせます。

service xinetd reload

systemd環境では、次のように実行できます。

systemctl reload xinetd.service

再読み込みに対応していない場合は、xinetdを再起動します。

service xinetd restart

または、次のように実行します。

systemctl restart xinetd.service

SysV initによる常駐サービスの起動制御

Webサーバーのように常時稼働するサービスは、inetdやxinetdではなく、SysV initスクリプトやsystemdのサービスユニットによって管理されます。

/etc/inittab

/etc/inittabは、従来のSysV init方式で、デフォルトのランレベルや各ランレベルで実行する処理などを定義する設定ファイルです。

ただし、個々のネットワークサービスの自動起動は、通常は/etc/inittabへ直接記述するのではなく、/etc/init.d/のスクリプトとランレベルごとのシンボリックリンクによって管理します。

主なディレクトリは次のとおりです。

/etc/init.d/
/etc/rc0.d/
/etc/rc1.d/
/etc/rc2.d/
/etc/rc3.d/
/etc/rc4.d/
/etc/rc5.d/
/etc/rc6.d/

/etc/rcN.d/には、/etc/init.d/以下のスクリプトへのシンボリックリンクが配置されます。

  • Sで始まるリンク:そのランレベルでサービスを開始する
  • Kで始まるリンク:そのランレベルでサービスを停止する

これらのリンクは手作業で変更するよりも、chkconfigやupdate-rc.dなどのコマンドを使って管理するのが一般的です。

serviceコマンド

serviceコマンドは、SysV initスクリプトを呼び出し、サービスをその場で開始・停止・再起動します。

service サービス名 操作

主な操作は次のとおりです。

操作説明
startサービスを開始する
stopサービスを停止する
restartサービスを再起動する
reload設定を再読み込みする
status稼働状態を確認する

たとえば、httpdを停止する場合は次のように実行します。

service httpd stop

状態を確認する場合は次のように実行します。

service httpd status

initスクリプトを直接実行することもできます。

/etc/init.d/httpd stop

serviceやinitスクリプトによる停止は、現在稼働しているサービスに対する操作です。これだけでは、次回のシステム起動時にサービスが再び起動する可能性があります。

chkconfigコマンド

chkconfigは、主にRed Hat系のSysV init環境で、各ランレベルにおけるサービスの自動起動を設定するコマンドです。

登録されているサービスと自動起動設定を一覧表示します。

chkconfig --list

特定のサービスだけを確認する場合は、サービス名を指定します。

chkconfig --list httpd

httpdの自動起動を無効化する場合は、次のように実行します。

chkconfig httpd off

自動起動を有効化する場合は次のとおりです。

chkconfig httpd on

対象のランレベルを明示することもできます。

chkconfig --level 2345 httpd off

この例では、ランレベル2・3・4・5でhttpdを自動起動しないように設定しています。

主な指定は次のとおりです。

指定説明
--listサービスの自動起動設定を表示する
--level ランレベル設定対象のランレベルを指定する
on自動起動を有効化する
off自動起動を無効化する

現在稼働しているhttpdを停止し、次回以降も自動起動しないようにするには、両方のコマンドを実行します。

service httpd stop
chkconfig httpd off

update-rc.dコマンド

Debian系のSysV init環境では、サービスの自動起動設定にupdate-rc.dを使用します。

apache2の自動起動を無効化する例は次のとおりです。

update-rc.d apache2 disable

自動起動を再び有効化する場合は次のように実行します。

update-rc.d apache2 enable

現在稼働しているサービスも停止する場合は、別途serviceコマンドを実行します。

service apache2 stop
update-rc.d apache2 disable

systemdによるサービスの無効化

systemd環境では、サービスの開始・停止と自動起動設定をsystemctlコマンドで管理します。

サービスの確認

現在稼働しているサービスを一覧表示します。

systemctl list-units --type=service --state=running

インストールされているサービスユニットと自動起動設定を確認します。

systemctl list-unit-files --type=service

特定のサービスの状態を確認する場合は、statusを使用します。

systemctl status httpd.service

サービスの停止

現在稼働しているサービスを停止します。

systemctl stop httpd.service

この操作だけでは自動起動設定は変更されません。

自動起動の無効化

システム起動時の自動起動を無効化します。

systemctl disable httpd.service

この操作だけでは、現在稼働しているサービスは停止しません。

現在のサービスを停止し、同時に自動起動も無効化するには、--nowオプションを使用します。

systemctl disable --now httpd.service

自動起動を再び有効化する場合は次のように実行します。

systemctl enable httpd.service

有効化と同時にサービスを開始する場合は次のとおりです。

systemctl enable --now httpd.service

disableとmaskの違い

disableはシステム起動時の自動起動を無効化しますが、手動操作やほかのユニットからの依存関係によって起動される可能性があります。

サービスを起動できないように、より強く無効化するにはmaskを使用します。

systemctl mask httpd.service

現在稼働中のサービスも停止する場合は次のように実行します。

systemctl mask --now httpd.service

マスクを解除するにはunmaskを使用します。

systemctl unmask httpd.service

maskはサービスを完全に起動不能にするため、依存関係にあるサービスへ影響しないかを確認してから使用します。


systemdのソケットアクティベーション

systemdでは、.socketユニットがポートやUNIXドメインソケットを監視し、接続があったときに対応する.serviceユニットを起動できます。この仕組みをソケットアクティベーションと呼びます。

ソケットユニットの一覧は次のコマンドで確認できます。

systemctl list-units --type=socket

自動起動設定を含めて確認する場合は次のように実行します。

systemctl list-unit-files --type=socket

ソケットユニットを停止する場合は次のとおりです。

systemctl stop example.socket

システム起動時の有効化も解除する場合は次のように実行します。

systemctl disable example.socket

停止と自動起動の無効化を同時に行う場合は、--nowを使用します。

systemctl disable --now example.socket

ソケットアクティベーションを使用するサービスでは、.serviceユニットだけを停止しても、ソケットへの接続をきっかけに再び起動する可能性があります。そのため、不要なサービスを無効化するときは、対応する.socketユニットの状態も確認します。

systemctl status example.service
systemctl status example.socket

必要に応じて.serviceユニットを停止し、.socketユニットを停止・無効化します。

systemctl stop example.service
systemctl disable --now example.socket

無効化後の確認

設定変更後は、サービスの状態と待ち受けポートを再確認します。

SysV init環境では次のように確認します。

service httpd status
chkconfig --list httpd

systemd環境では次のように確認します。

systemctl status httpd.service
systemctl is-enabled httpd.service
systemctl is-active httpd.service

待ち受けポートも再確認します。

ss -lntup

systemdの主な状態表示は次のとおりです。

表示意味
active現在稼働している
inactive現在稼働していない
enabledenable用のリンクが設定され、設定された起動契機で起動できる
disabledenable用のリンクが設定されていない。依存関係など別の起動契機による起動はあり得る
masked起動できないようにマスクされている

TCPラッパーとファイアウォール

/etc/hosts.allowと/etc/hosts.deny(TCPラッパー)

TCPラッパーは、接続元のホスト名やIPアドレスに基づいて、対応するネットワークサービスへのアクセスを許可・拒否する仕組みです。

ただし、TCPラッパーが機能するには対象サービスがTCPラッパーに対応している必要があります。現在のディストリビューションやサービスではlibwrap対応が提供されない場合もあるため、設定前に対象サービスの対応状況を確認します。

設定には、次の2つのファイルを使用します。

  • /etc/hosts.allow:許可するアクセスを記述する
  • /etc/hosts.deny:拒否するアクセスを記述する

アクセスの判定順序

アクセスの可否は、次の順序で判定されます。

  1. /etc/hosts.allowを確認する

一致するルールがあれば、アクセスを許可する

  1. /etc/hosts.allowに一致するルールがなければ、/etc/hosts.denyを確認する

一致するルールがあれば、アクセスを拒否する

  1. どちらのファイルにも一致するルールがなければ、アクセスを許可する

したがって、同じアクセスが両方のファイルのルールに一致した場合は、先に確認される/etc/hosts.allowのルールが優先され、アクセスは許可されます。

また、どちらのファイルにも一致しない場合の既定の動作は「許可」である点に注意が必要です。

基本的な書式

/etc/hosts.allowと/etc/hosts.denyは、どちらも次の書式で記述します。

サービス名 : クライアント
  • サービス名:sshdなどのデーモン名を指定する
  • クライアント:接続元のホスト名やIPアドレスを指定する
  • 複数指定する場合は、空白またはカンマで区切る
  • #から行末まではコメントとして扱われる

サービス名には、ポート番号ではなくデーモン名を指定します。

代表的な指定方法は次のとおりです。

指定例意味
ALLすべて
192.168.1.10指定したIPアドレス
192.168.1.192.168.1で始まるIPアドレス
host.example.com指定したホスト名
.example.comexample.comドメイン配下のホスト
EXCEPT指定した対象を除外する

設定例

TCPラッパーに対応したsshdで、特定の接続元からのSSHアクセスだけを許可し、それ以外を拒否する場合は、次のように設定します。

/etc/hosts.allow

# 特定のIPアドレスからのSSHアクセスを許可
sshd : 192.168.1.10

# 192.168.2.0/24に相当する範囲からのSSHアクセスを許可
sshd : 192.168.2.

# example.comドメイン配下からのSSHアクセスを許可
sshd : .example.com

/etc/hosts.deny

# 上記で許可されなかった、すべてのアクセスを拒否
ALL : ALL

この設定では、TCPラッパーに対応しているサービスについて、次のように判定されます。

  • 192.168.1.10からのSSHアクセス:許可
  • 192.168.2.で始まるIPアドレスからのSSHアクセス:許可
  • .example.comに一致するホストからのSSHアクセス:許可
  • それ以外のSSHアクセス:拒否
  • 明示的に許可していないその他の対応サービスへのアクセス:拒否

/etc/hosts.denyに次のように記述し、原則としてすべて拒否したうえで、必要なアクセスだけを/etc/hosts.allowで許可する構成がよく使用されます。

ALL : ALL

EXCEPTを使用した例

EXCEPTを使用すると、指定した範囲から一部を除外できます。

sshd : 192.168.1. EXCEPT 192.168.1.100

このルールでは、192.168.1.で始まる接続元からのSSHアクセスを許可しますが、192.168.1.100だけは許可対象から除外します。

ただし、EXCEPTで除外したアクセスを拒否するには、/etc/hosts.deny側に一致する拒否ルールが必要です。例えば、次の設定であれば192.168.1.100からのSSHアクセスは拒否されます。

ALL : ALL

TCPラッパー利用時の注意点

TCPラッパーによるアクセス制御が機能するのは、次のようなTCPラッパー対応サービスだけです。

  • tcpdを経由して起動されるサービス
  • libwrapを利用するように実装されたサービス

TCPラッパーに対応していないサービスには、/etc/hosts.allowや/etc/hosts.denyを設定しても影響しません。

試験では、特に次の判定順序を押さえておきましょう。

hosts.allowで一致 → 許可
hosts.denyで一致  → 拒否
どちらにも一致しない → 許可

iptables

iptablesは、Linuxカーネルのパケットフィルタリング機能(netfilter)を操作するためのIPv4向けコマンドです。TCPラッパーがサービス単位・アプリケーション層での制御であるのに対し、iptablesはより下位のネットワーク層・トランスポート層で、送信元・宛先のIPアドレスやポート番号などの条件に基づいてパケットの通過・拒否を制御します。この違いにより、iptablesはTCPラッパーに対応していないサービスへの通信も含めて制御できます。IPv6のパケットフィルタリングには、従来はip6tablesを使用します。

ルールはチェーン(INPUT・OUTPUT・FORWARDなど)ごとに定義され、チェーン内のルールは上から順に評価され、ACCEPT・DROP・REJECTなどの最終判断を行うターゲットに一致した時点で、そのパケットに対する処理が確定します。

firewalld

firewalldは、iptablesをより扱いやすくするために作られた、動的なファイアウォール管理デーモンです。多くのディストリビューションで広く利用されるファイアウォール管理の仕組みの一つです。ネットワークインターフェースを「信頼度」に応じたゾーン(public・internal・trustedなど)に割り当て、ゾーンごとに許可するサービス・ポートを設定する、という考え方が特徴です。

設定操作は主にfirewall-cmdコマンドで行います。

firewall-cmd --add-service=http

ゾーンを指定しないこのコマンドは、既定ゾーンに対して設定を行います。特定のゾーンを対象にする場合は、--zone=ゾーン名を指定します。

ここで重要なのが、「今すぐ」の設定と「再起動後も残る恒久的な」設定が分かれているという点です。

  • 上記のように--permanentを付けずに実行すると、その場で即座に反映されますが、firewalldの再起動やシステムの再起動で設定が失われます(一時的な設定)。
  • --permanentを付けて実行すると恒久設定として保存されますが、それだけではすぐには反映されず、--reloadを実行するか、システムを再起動する必要があります。
  • 一時的な設定を、後から恒久設定として反映させたい場合は--runtime-to-permanentオプションを使います。

「一時的な変更」と「恒久的な変更」が別々に管理されており、一方だけを変更しても他方には影響しない、という点は、firewalldの出題で特によく問われるポイントです。

firewalldを使用する環境では、iptablesコマンドでルールを直接変更する操作を並行して行わないようにします。firewalldは多くの環境で内部的にiptablesまたはnftablesの仕組みを利用して実際のパケット処理を行っており、直接追加したルールはfirewalldの再読み込みなどで失われたり、意図しないルール構成になったりする可能性がありますfirewalldは多くの環境で内部的にiptablesまたはnftablesの仕組みを利用して実際のパケット処理を行っています。「firewalldとiptablesは全く無関係の独立した機能」ではなく、firewalldはiptables(またはnftables)をより扱いやすく抽象化したものと理解しておくと整理しやすくなります。[2]。


補足

  1. 具体的にどのサービスがシェルを経由せずに動作するかは、そのサービス自体の実装に依存します。「ログインシェルをnologinにすれば、そのアカウントに関するアクセスを完全に遮断できる」という単純化はできません。 ↩
  2. firewalldは多くの環境で内部的にiptablesまたはnftablesの仕組みを利用して実際のパケット処理を行っています。「firewalldとiptablesは全く無関係の独立した機能」ではなく、firewalldはiptables(またはnftables)をより扱いやすく抽象化したものと理解しておくと整理しやすくなります。 ↩