著者は、 Write for DOnations プログラムの一環として、 Free and Open SourceFundを選択して寄付を受け取りました。
序章
サンドボックスは、通常の操作中に対話する必要のないシステムの部分からプログラムまたはプロセスを分離することに焦点を当てたコンピューターセキュリティ技術です。 新しいプログラムが開始されると、それはそれが実行されるユーザーのすべての機能を備えています。 これらの能力は、プログラムがその機能を実行するために必要な能力をはるかに超えていることがよくあります。 これは、悪意のある攻撃者がプログラムを操作して、プログラムが通常は実行しないことを実行するために未使用の機能の一部にアクセスする場合に、セキュリティの問題を引き起こす可能性があります。
サンドボックス化の目的は、プログラムに必要な機能とリソースを正確に特定し、それ以外のすべてをブロックすることです。
ツールのシステム管理スイートsystemdは、プログラムとプロセスを開始、停止、および管理するために、ほとんどすべての主要なLinuxディストリビューションで使用されています。 開始するプロセスがホストシステムにアクセスする方法を制限する多くのサンドボックスオプションがあり、より安全になります。
このチュートリアルの目的は、可能な限り厳密なサンドボックス環境を作成することではなく、推奨され、簡単に有効にできる設定を使用して、システムをより安全にすることです。
このチュートリアルでは、Ubuntu 20.04でsystemdのサンドボックス技術を使用して、これらの技術を実装およびテストするための効率的なワークフローを実現する方法の実践的なデモンストレーションを実行します。 systemdを使用するLinuxシステムで実行されるプロセスはすべて、これらの手法を使用してより安全にすることができます。
前提条件
このガイドを開始するには、次のものが必要です。
- Ubuntu20.04システム。
- sudo権限を持つroot以外のユーザー。 Ubuntu 20.04でこれを行う方法については、 Ubuntu20.04での初期サーバーセットアップに従ってください。
- systemdを使用したプロセスの管理にある程度精通している。 Essentialsについては、 Systemd Essentials:サービス、ユニット、およびジャーナルガイドの操作を参照してください。
- systemdユニットファイルの基本的な理解が役立ちます。 詳細については、Systemdユニットとユニットファイルについてガイドを参照してください。
ステップ1—lighttpdをインストールする
このチュートリアルでは、 lighttpdWebサーバーをサンドボックス化します。 lighttpdは、他のソフトウェアよりも安全性が低いために選択されませんでしたが、サンドボックス化が容易な単一の機能を備えた小さなプログラムであるためです。 これにより、学習アプリケーションに最適です。
システムを更新して開始しましょう。
- sudo apt update
y
と入力する前に、システムでアップグレードされるパッケージを確認してください。
- sudo apt upgrade
次にlighttpdをインストールします。
- sudo apt install lighttpd
このインストールプロセスにより、lighttpdのsystemdサービスファイルが自動的にインストールされて有効になります。 これにより、システムの再起動時にlighttpdが起動します。
システムにlighttpdをインストールして実行したので、サンドボックス化を開始するときに使用するsystemdツールについて理解します。
ステップ2—システムの準備
このステップでは、使用するsystemdコマンドに精通し、プロセスを効率的にサンドボックス化できるようにシステムを準備します。
systemdは、それぞれ異なる名前を持つ一連のツールの包括的な名前です。 使用するのはsystemctl
とjournalctl
の2つです。 systemctl
はプロセスとそのサービスファイルを管理し、journalctl
はシステムログと対話します。
systemdは、サービスファイルを使用して、プロセスの管理方法を定義します。 systemdは、ファイルシステム内のいくつかの場所からこれらのファイルをロードします。 次のコマンドは、アクティブなサービスファイルの場所を表示し、使用中のオーバーライドを表示します。
- sudo systemctl cat process.service
process
を作業中のプロセスに置き換える必要があります。 ここではlighttpdが使用されています:
- sudo systemctl cat lighttpd.service
これは前のコマンドからの出力です:
Output# /lib/systemd/system/lighttpd.service
[Unit]
Description=Lighttpd Daemon
After=network-online.target
[Service]
Type=simple
PIDFile=/run/lighttpd.pid
ExecStartPre=/usr/sbin/lighttpd -tt -f /etc/lighttpd/lighttpd.conf
ExecStart=/usr/sbin/lighttpd -D -f /etc/lighttpd/lighttpd.conf
ExecReload=/bin/kill -USR1 $MAINPID
Restart=on-failure
[Install]
WantedBy=multi-user.target
この出力は、サービスファイルが/lib/systemd/system/lighttpd.service
にあり、使用中のオーバーライドオプションがないことを示しています。 オーバーライドオプションは、ベースサービスファイルに追加または変更します。 専用のオーバーライドファイルを使用してlighttpdをサンドボックス化するためにオーバーライドを使用します。
オーバーライドファイルは/etc/systemd/system/process.service.d/override.conf
にあります。 systemdには専用のedit
コマンドがあり、正しい場所にオーバーライドファイルを作成し、エディターを保存して終了した後にsystemctl daemon-reload
を実行します。 systemctl daemon-reload
は、作成した新しい構成を使用するようにsystemdに指示します。
systemdeditコマンドの形式は次のとおりです。
- sudo systemctl edit process.service
このコマンドを実行すると、systemdは通常デフォルトのCLIエディターを選択しますが、常にそうであるとは限らず、viまたはedにいることもあります。 SYSTEMD_EDITOR
シェル変数を設定することにより、systemdが使用するエディターを構成できます。
~/.bashrc
ファイルに行を追加して、このシェル変数を設定します。 このファイルをテキストエディタで開きます。
- nano ~/.bashrc
そして、次の行を追加します。
export SYSTEMD_EDITOR=editor
editor
をお好みのCLIエディターに変更します。 nanoエディターを使用するために設定された行は次のとおりです。
export SYSTEMD_EDITOR=nano
echo
コマンドを使用してログアウトし、再度ログインした後、これが設定されていることを確認します。
- echo $SYSTEMD_EDITOR
このコマンドは、設定したエディターの名前を出力します。
SYSTEMD_EDITOR
シェル変数はユーザーのシェルでのみ設定され、sudo
によって開かれるrootのシェルでは設定されません。 この変数をrootのシェルに渡すには、sudo -E
を使用してsystemctl edit
を呼び出します。
- sudo -E systemctl edit process.service
最後の推奨事項は、変更によって発生したエラーを表示することにより、サンドボックスのデバッグを容易にします。 これらのエラーは、journalctlコマンドでアクセスされるシステムログに記録されます。
サンドボックス化中に、サンドボックス化しようとしているプロセスを中断する多くの変更を加えます。 そのため、2つ目の端末を開いて、システムログの追跡専用にすることをお勧めします。 これにより、システムログを再度開く時間を節約できます。
次のコマンドを実行して、2番目の端末のシステムログを追跡します。
- sudo journalctl -f -u process.service
-f
:システムログを追跡または追跡して、新しい行がすぐに表示されるようにします。-u process.service
:サンドボックス化するprocess
のログ行のみを表示します。
以下は、lighttpdのエラーのみを出力するために実行する必要があるものです。
- sudo journalctl -f -u lighttpd.service
次に、override.conf
ファイルの編集を開始し、lighttpdのサンドボックス化を開始します。
ステップ3—ユーザーとグループを強制する
このステップでは、lighttpdを実行するroot以外のユーザーを設定します。
デフォルト設定では、lighttpdは root ユーザーとして実行を開始し、www-dataユーザーとグループに変更します。 これは問題です。lighttpdがrootとして実行されている間は、rootが実行できることは何でも実行できるからです。
systemdは、root以外のユーザーとしてプロセスを開始および実行する機能を提供するため、この問題を回避できます。
最初のターミナルセッションに戻り、次のコマンドを実行してオーバーライドファイルの編集を開始します。
- sudo -E systemctl edit lighttpd.service
ここで、次の行を追加します。
[Service]
User=www-data
Group=www-data
[Service]
:次のオプションを[Service]
セクションに適用する必要があることをsystemdに通知します。User=www-data
:プロセスを開始するユーザーを定義します。Group=www-data
:プロセスを開始するグループを定義します。
次に、エディタを保存して終了し、次のコマンドでlighttpdを再起動します。
- sudo systemctl restart lighttpd.service
root
権限を使用してルートが所有する場所にPIDファイルを書き込んでいたため、lighttpdを起動できません。 www-data ユーザーは、rootが所有するディレクトリに書き込むことができません。 この問題は、2番目のターミナルセッションに表示されるシステムログに示されます。
journalctl error messageAug 29 11:37:35 systemd lighttpd[7097]: 2020-08-29 11:37:35: (server.c.1233) opening pid-file failed: /run/lighttpd.pid Permission denied
この問題の解決は、サンドボックス化のプロセスに従います。
- サンドボックス制限を実装します。
- プロセスを再開し、エラーを確認します。
- エラーを修正します。
次に、このセクションで設定したユーザーとグループの制限を適用しながら、PIDファイルの問題を解決します。
ステップ4—PIDファイルの管理
PIDファイルは、実行中のプロセスのPIDまたはプロセス識別番号を含むファイルです。 lighttpdのような長時間実行されるプログラムは、それらを使用して独自のプロセスを管理します。 前のセクションで発生した問題は、/run/
がroot によって所有されているため、lighttpdがPIDファイルを/run/lighttpd.pid
に書き込めないことでした。
systemdには、この問題に対するRuntimeDirectory
オプションがあります。これを使用して、lighttpdにPIDファイルを書き込める場所を指定します。
RuntimeDirectory
オプションを使用すると、systemdがlighttpdを起動したときにステップ3で設定したユーザーとグループで作成される/run/
の下のディレクトリを指定できます。 lighttpdは、 rootの権限を必要とせずに、そのPIDをこのディレクトリに書き込むことができます。
まず、ステップ3 で使用したのと同じコマンドを使用して、オーバーライドファイルを開いて編集します。
- sudo -E systemctl edit lighttpd.service
次に、オーバーライドファイルにすでに追加した2行の下に次の行を追加します。
RuntimeDirectory=lighttpd
エディターを保存して終了します。
RuntimeDirectory
を使用してディレクトリへのフルパスを追加するのではなく、/run/
の下のディレクトリの名前のみを追加します。 この場合、systemdが作成するディレクトリは/run/lighttpd/
です。
次に、/run/
ではなく新しいディレクトリ/run/lighttpd/
にPIDファイルを書き込むようにlighttpdを設定する必要があります。
テキストエディタでlighttpdの設定ファイルを開きます。
- sudo nano /etc/lighttpd/lighttpd.conf
次の行を変更します。
server.pid-file = "/run/lighttpd.pid"
に:
server.pid-file = "/run/lighttpd/lighttpd.pid"
エディターを保存して終了します。
ここで、lighttpdを再起動します。
- sudo systemctl restart lighttpd.service
rootの機能の1つを必要とする何かを実行できないため、起動しません。 次に、この新しい問題を解決します。
ステップ5—ルートの機能を借用する
システムログの次の行は、lighttpdの起動を停止した問題を説明しています。
journalctl error messageAug 29 12:07:22 systemd lighttpd[7220]: 2020-08-29 12:07:22: (network.c.311) can't bind to socket: 0.0.0.0:80 Permission denied
root のみが、番号1024
未満のネットワークポートを開くことができます。 lighttpdはHTTPポート80
を開こうとしていますが、 www-data ユーザーがそれを行うことができないため、拒否されています。
この問題は、lighttpdプロセスに rootのパワーのごく一部、つまり1024
より下のポートを開くことで解決されます。
rootの「力」は、「能力」と呼ばれる能力に分けられます。 root ユーザーはすべての機能を備えているため、何でもできます。 rootのパワーアップを機能に分割することは、それらを非rootプロセスに個別に与えることができることを意味します。 これにより、そのプロセスは完全な root ユーザーを必要とする何かを実行できますが、通常のユーザーはrootの機能の1つを使用できるようになります。
プロセスにrootの機能の1つ以上を提供するsystemdオプションは、AmbientCapabilities
オプションです。
オーバーライドファイルを開きます。
- sudo -E systemctl edit lighttpd.service
次に、すでに追加した行の下に次の行を追加します。
AmbientCapabilities=CAP_NET_BIND_SERVICE
CAP_NET_BIND_SERVICE
機能を使用すると、プロセスは1024
の下のポートを開くことができます。
ファイルを保存して終了します。
これでlighttpdを起動できるようになります。
これで、デフォルト設定よりも安全にしたlighttpdWebサーバーが機能するようになりました。 systemdが提供するサンドボックスオプションには、ターゲットプロセスをさらに安全にするために使用できるものがあります。 次のセクションでは、これらのいくつかについて説明します。
次のステップでは、lighttpdがファイルシステムでアクセスできるものを制限します。
ステップ6—ファイルシステムをロックダウンする
lighttpdプロセスはwww-dataユーザーとして実行されるため、www-dataが読み取りおよび書き込みを許可されているシステム上の任意のファイルにアクセスできます。 www-data の場合、それほど多くはありませんが、lighttpdが必要とする以上のものです。
最初で最も簡単なサンドボックス設定は、ProtectHome
オプションです。 このオプションは、プロセスが/home/
の下にあるものに対して読み取りまたは書き込みを行うのを停止します。 lighttpdは/home/
の下にあるものにアクセスする必要がないため、これを実装すると、lighttpdに影響を与えることなくすべてのプライベートファイルを保護できます。
オーバーライドファイルを開きます。
- sudo -E systemctl edit lighttpd.service
次に、ファイルの最後に次の行を追加します。
ProtectHome=true
エディターを保存して終了し、lighttpdを再起動して、次のコマンドで期待どおりに機能していることを確認します。
- sudo systemctl restart lighttpd.service
/home/
を保護しましたが、それでもファイルシステムの残りの部分は残ります。 これは、プロセスがファイルシステムの一部に書き込むのを停止するProtectSystem
オプションで処理されます。
ProtectSystem
オプションには、保護レベルを上げる3つの設定があります。 それらは次のとおりです。
true
:次のディレクトリを読み取り専用に設定します:- / usr / / boot / / efi /
full
:次のディレクトリを読み取り専用に設定します:- / usr / / boot / / efi / / etc /
strict
:次のディレクトリを読み取り専用に設定します。- ファイルシステム全体
より高いレベルの保護はより安全であるため、オーバーライドファイルに次の行を追加してProtectSystem
オプションをstrict
に設定します。
ProtectSystem=strict
エディターを保存して終了し、次のコマンドでlighttpdを再起動します。
- sudo systemctl restart lighttpd.service
lighttpdは、ログファイルを/var/log/lighttpd/
に書き込む必要があり、strict
設定でそれが禁止されているため、起動できません。 システムログの次の行は、問題を示しています。
journalctl error messageAug 29 12:44:41 systemd lighttpd[7417]: 2020-08-29 12:44:41: (server.c.752) opening errorlog '/var/log/lighttpd/error.log' failed: Read-only file system
この問題は、LogsDirectory
オプションを指定したsystemdで予期されていました。 プロセスがログを書き込むことを許可されている/var/log/
の下のディレクトリの名前を取ります。
最初のターミナルセッションでオーバーライドファイルを再度開きます。
- sudo -E systemctl edit lighttpd.service
lighttpdログディレクトリは/var/log/lighttpd/
なので、オーバーライドファイルの最後に次の行を追加します。
LogsDirectory=lighttpd
エディターを保存して終了し、lighttpdを再起動します。
- sudo systemctl restart lighttpd.service
これでlighttpdを起動して実行できるようになります。
注: lighttpd以外のプロセスをサンドボックス化し、プロセスが/var/log/
の外部の特定のディレクトリへの書き込みアクセスを許可する場合は、ReadWritePathsオプションを使用します。
次のステップでは、lighttpdプロセスがシステムの他の部分と対話する方法を制限するために、許可されているシステムコールを制限します。
ステップ7—システムコールを制限する
システムコールは、プログラムがカーネルに何かを要求する方法です。 システムコールの数は非常に多く、ファイルの読み取り、書き込み、削除などのアクション、ファイルシステムのマウント、スポーンプロセス、再起動などのハードウェア関連のタスクが含まれます。
systemdは、lighttpdのようなプロセスが通常使用し、使用しないコールを除外するシステムコールのグループを作成しました。 ブロックされたシステムコールは、ファイルシステムのマウントやシステムの再起動などですが、lighttpdでは実行する必要はありません。
まず、オーバーライドファイルを開きます。
- sudo -E systemctl edit lighttpd.service
ファイルの最後に次の行を追加して、SystemCallFilter
オプションを使用して@system-service
グループを設定します。
SystemCallFilter=@system-service
エディターを保存して終了し、lighttpdを再起動します。
- sudo systemctl restart lighttpd.service
次のセクションでは、残りの推奨サンドボックスオプションを適用します。
ステップ8—追加オプションの実装
systemdのドキュメントでは、lighttpdのような長時間実行されるネットワークプロセスに対して次のオプションを有効にすることを推奨しています。 これらの設定はすべてオプションですが、それぞれがサンドボックス化するプロセスをより安全にするため、可能であれば使用する必要があります。
これらのオプションを一度に1つずつ有効にし、各オプションの後でプロセスを再開する必要があります。 それらをすべて一度に追加すると、問題のデバッグははるかに困難になります。
以下の推奨オプションには、それらの機能の簡単な説明が付いています。 これらの行を、すでに追加した行の下のオーバーライドファイルに追加します。
NoNewPrivileges=true
このオプションは、サンドボックス化されたプロセスとその子が新しい特権を取得するのを停止します。
ProtectKernelTunables=true
このオプションは、プロセスがカーネル変数を変更するのを停止します。
ProtectKernelModules=true
このオプションは、プロセスがカーネルモジュールをロードまたはアンロードするのを停止します。
ProtectKernelLogs=true
このオプションは、プロセスがカーネルログに直接読み書きするのを停止します。 ログメッセージを記録するには、システムログアプリケーションを使用する必要があります。
ProtectControlGroups=true
このオプションは、プロセスによるシステム制御グループの変更を停止します。
MemoryDenyWriteExecute=true
このオプションは、システムのメモリで実行されているコードをプロセスが変更するのを停止します。
RestrictSUIDSGID=true
このオプションは、プロセスがファイルまたはディレクトリにset-user-ID(SUID)またはset-group-ID(SGID)を設定するのを停止します。 この機能は、特権を高めるために悪用される可能性があります。
KeyringMode=private
このオプションは、プロセスが同じユーザーとして実行されている他のプロセスのカーネルキーリングにアクセスするのを停止します。
ProtectClock=true
このオプションは、プロセスがハードウェアおよびソフトウェアのシステムクロックを変更するのを停止します。
RestrictRealtime=true
このオプションは、CPUを過負荷にするために悪用される可能性のあるリアルタイムスケジューリングをプロセスが有効にするのを停止します。
PrivateDevices=true
このオプションは、プロセスがストレージデバイスやUSBデバイスなどのシステムに接続されている物理デバイスにアクセスするのを停止します。
PrivateTmp=true
このオプションは、プロセスにプライベート/tmp/
および/var/tmp/
ディレクトリの使用を強制します。 これにより、プロセスは、これらの共有システムディレクトリに保存されている他のプログラムの一時ファイルを読み取ることができなくなります。
ProtectHostname=true
このオプションは、プロセスがシステムのホスト名を変更するのを停止します。
サンドボックス化したプロセスは、デフォルト構成よりもはるかに安全になりました。 これで、これらの手法を使用して、Linuxシステムで保護する必要のある他のプロセスに使用できます。
結論
この記事では、systemdサンドボックスオプションを使用してlighttpdプログラムをより安全にしました。 これらの手法は、systemdが管理する任意のプロセスで使用できるため、システムのセキュリティを継続的に向上させることができます。
サンドボックスおよびその他のセキュリティオプションの全リストは、systemdのオンラインドキュメントにあります。 また、DigitalOceanコミュニティでセキュリティトピックをさらにチェックしてください。