Ubuntu20.04でSystemdを使用してプロセスをサンドボックス化する方法
序章
サンドボックスは、通常の操作中に対話する必要のないシステムの部分からプログラムまたはプロセスを分離することに焦点を当てたコンピューターセキュリティ技術です。 新しいプログラムが開始されると、それはそれが実行されるユーザーのすべての能力を備えています。 これらの能力は、プログラムがその機能を実行するために必要な能力をはるかに超えていることがよくあります。 これは、悪意のある攻撃者がプログラムを操作して、プログラムが通常は実行しないことを実行するために未使用の機能の一部にアクセスする場合に、セキュリティの問題を引き起こす可能性があります。
サンドボックス化の目的は、プログラムに必要な機能とリソースを正確に特定し、それ以外のすべてをブロックすることです。
ツールのシステム管理スイート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は、それぞれ異なる名前を持つ一連のツールの包括的な名前です。 使用する2つは systemctl
と journalctl
. 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
保存してエディターを終了した後。 The systemctl daemon-reload
作成した新しい構成を使用するようにsystemdに指示します。
systemdeditコマンドの形式は次のとおりです。
- sudo systemctl edit process.service
このコマンドを実行すると、systemdは通常デフォルトのCLIエディターを選択しますが、常にそうであるとは限らず、viまたはedにいることもあります。 systemdが使用するエディターを構成するには、 SYSTEMD_EDITOR
シェル変数。
に行を追加して、このシェル変数を設定します ~/.bashrc
ファイル。 このファイルをテキストエディタで開きます。
- nano ~/.bashrc
そして、次の行を追加します。
export SYSTEMD_EDITOR=editor
変化する editor
お好みのCLIエディターに。 nanoエディターを使用するために設定された行は次のとおりです。
export SYSTEMD_EDITOR=nano
ログアウトしてから再度ログインした後、これが設定されていることを確認してください。 echo
指図:
- echo $SYSTEMD_EDITOR
このコマンドは、設定したエディターの名前を出力します。
The SYSTEMD_EDITOR
シェル変数はユーザーのシェルでのみ設定され、rootのシェルでは設定されません。 sudo
. この変数をrootのシェルに渡すには、 systemctl edit
を使用して sudo -E
:
- 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]
:次のオプションをに適用する必要があることをsystemdに通知します[Service]
セクション。User=www-data
:プロセスを開始するユーザーをとして定義します。Group=www-data
:プロセスを開始するグループを定義します。
次に、エディタを保存して終了し、次のコマンドでlighttpdを再起動します。
- sudo systemctl restart lighttpd.service
lighttpdは、を使用していたため、起動できません。 root
rootが所有する場所にPIDファイルを書き込む権限。 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のような長時間実行されるプログラムは、それらを使用して独自のプロセスを管理します。 前のセクションで発生した問題は、lighttpdがPIDファイルをに書き込むことができなかったことです。 /run/lighttpd.pid
、 なぜなら /run/
rootが所有しています。
systemdには RuntimeDirectory
この問題のオプション。lighttpdにPIDファイルを書き込める場所を指定するために使用します。
The RuntimeDirectory
オプションを使用すると、下のディレクトリを指定できます /run/
これは、systemdがlighttpdを起動したときに、ステップ3で設定したユーザーとグループで作成されます。 lighttpdは、 rootの権限を必要とせずに、そのPIDをこのディレクトリに書き込むことができます。
まず、ステップ3 で使用したのと同じコマンドを使用して、オーバーライドファイルを開いて編集します。
- sudo -E systemctl edit lighttpd.service
次に、オーバーライドファイルにすでに追加した2行の下に次の行を追加します。
RuntimeDirectory=lighttpd
エディターを保存して終了します。
ディレクトリへのフルパスを追加しないでください RuntimeDirectory
、下のディレクトリの名前のみ /run/
. この場合、systemdが作成するディレクトリは /run/lighttpd/
.
PIDファイルを新しいディレクトリに書き込むようにlighttpdを設定する必要があります /run/lighttpd/
それ以外の /run/
.
テキストエディタで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
The 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
オプション。プロセスがファイルシステムの一部に書き込むのを停止します。
The 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
この問題は、systemdによって予期されていました。 LogsDirectory
オプション。 下のディレクトリの名前を取ります /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コミュニティでセキュリティトピックをさらにチェックしてください。