最も人気のあるLinuxディストリビューションの最近のバージョンはすべて、 systemd
を使用しています。 マシンを起動し、システムサービスを管理します。 Systemd
およびサービスの開始を容易にするいくつかの機能を提供します より安全に。これはまれな組み合わせであり、この記事では、 systemd
を使用することが有用である理由を示しています。 サービスのリソースとサンドボックスを管理します。
正当化
では、なぜ systemd
を使用する必要があるのでしょうか。 セキュリティサンドボックス化のために?まず、この機能の各ビットは、スクリプト化して任意の方法で組み合わせることができる既存のよく知られたツールを通じてすでに公開されていると主張する人もいるかもしれません。次に、特にC / C ++やその他の低水準言語で記述されたプログラムの場合、適切なシステムコールを直接使用して、特定のサービスのニーズに合わせて慎重に調整された無駄のない実装を実現できます。
主な理由は4つあります:
1。セキュリティは難しいです。 サービスマネージャで一元化された実装は、それを利用するサービスを大幅に簡素化できることを意味します。間違いなく、この一元化された実装は複雑ですが、広く使用されているため、十分にテストされています。何千ものサービスで再利用されていると考えると、全体 システムの複雑さが軽減されます。
2。セキュリティプリミティブはシステムによって異なります。 Systemd
ハードウェアアーキテクチャ、カーネルバージョン、およびシステム構成の違いをスムーズにします。
サービスの強化を提供する機能は、特定のシステムで可能な範囲で実装されます。たとえば、 systemd
ユニットには、AppArmorとSELinuxの両方の構成が含まれている場合があります。 1つ目はUbuntu/Debianシステムで使用され、2つ目はFedora / RHEL / CentoOSで使用され、MACシステムを有効にしないディストリビューションでも使用されません。この柔軟性のもう1つの側面は、これらの機能をのみとして信頼できないことです。 封じ込めメカニズム(またはそのようなサービスは、必要なすべての機能をサポートするシステムでのみ使用されます)。
3。セキュリティには、システムを低レベルでいじる必要があります。 サービスマネージャーが提供する機能は、サービスの実装言語に依存しないため、シェルやPythonなどの便利な言語でサービスを記述し、それをロックするのは簡単です。
>4。セキュリティには特権が必要です。 これは逆説ですが、特権を奪うには特権が必要です。たとえば、ファイルシステムのビューを制限するカスタムマウント名前空間を設定するには、多くの場合、rootである必要があります。別の例として、HTTPデーモンは、多くの場合、rootとして開始され、低い番号のポートを開くことができます。また、低い番号のポートは、セキュリティの名目で制限されています。とにかくサービスマネージャーは最高の特権で実行する必要がありますが、サービスは実行すべきではありません。多くの場合、強化セットアップがより高い特権を必要とする唯一の理由です。このフェーズでのサービスの実装にバグがあると、危険な場合があります。セットアップをサービスマネージャーにオフロードすることで、昇格された特権のこの初期段階なしでサービスを開始できます。
これに関連して、最近リリースされたFedora 32には、C、C ++、Python、Java、Ocaml、Perl、Ruby、Lua、Tcl、Erlangなどで記述されたサービスを開始するための約1800の異なるユニットファイルが含まれています。> systemd 。
[systemdについてもっと知りたいですか?さらに役立つヒントについては、systemdのチートシートをダウンロードしてください。 ]
サービスを開始するためのいくつかの同等の方法
最も一般的には、 systemd
サービスはユニットファイルを介して定義されます :実行するコマンドとさまざまな設定を宣言するini形式のテキストファイル。このユニットファイルを編集した後、 systemctl daemon-reload
新しい設定をロードするためにマネージャを突くために呼び出される必要があります。デーモンからの出力はジャーナルに到達し、別のコマンドを使用して表示します。コマンドをインタラクティブに実行する場合、そのすべてがあまり便利ではありません。 systemd-run
commandは、ユーザーに代わってコマンドを開始するようにマネージャーに指示します。これは、インタラクティブに使用するための優れた代替手段です。実行するコマンドは、 sudo
と同様に指定されます 。最初の位置引数とそれ以降のすべてが実際のコマンドであり、先行するオプションはすべて systemd-run
によって解釈されます。 自体。 systemd-run
コマンドには、-uid
などの特定の設定を指定するオプションがあります および--gid
ユーザーとグループのために。 -E
オプションは環境変数を設定し、「キャッチオール」オプションは -p
ユニットファイルと同様に、任意のキーと値のペアを受け入れます。
$ systemd-run whoami
Running as unit: run-rbd26afbc67d74371a6d625db78e33acc.service
$ journalctl -u run-rbd26afbc67d74371a6d625db78e33acc.service
journalctl -u run-rbd26afbc67d74371a6d625db78e33acc.service
-- Logs begin at Thu 2020-04-23 19:31:49 CEST, end at Mon 2020-04-27 13:22:35 CEST. --
Apr 27 13:22:18 fedora systemd[1]: Started run-rbd26afbc67d74371a6d625db78e33acc.service.
Apr 27 13:22:18 fedora whoami[520662]: root
Apr 27 13:22:18 fedora systemd[1]: run-rbd26afbc67d74371a6d625db78e33acc.service: Succeeded.
systemd-run -t
コマンドの標準の入力、出力、およびエラーストリームを呼び出し元の端末に接続します。これは、コマンドをインタラクティブに実行するのに最適です(サービスプロセスは引き続きマネージャーの子であることに注意してください)。
$ systemd-run -t whoami
Running as unit: run-u53517.service
Press ^] three times within 1s to disconnect TTY.
root
一貫した環境
ユニットは常に慎重に定義された環境で起動します。 systemctl
を使用してユニットを起動する場合 またはsystemd-run
、コマンドは常にマネージャーの子として呼び出されます。シェルの環境は、サービスコマンドが実行される環境には影響しません。ユニットファイルで指定できるすべての設定がsystemd-run
でサポートされているわけではありません 、しかしほとんどはそうです、そして私たちがそのサブセットに固執する限り、ユニットファイルと systemd-run
を介した呼び出し 同等です。実際、 systemd-run
その場で一時ユニットファイルを作成します。
例:
$ sudo systemd-run -M rawhide -t /usr/bin/grep PRETTY_NAME= /etc/os-release
ここでは、 sudo
PAMと通信して特権の昇格を許可してから、 systemd-run
を実行します ルートとして。次に、 systemd-run
rawhideという名前のマシンに接続します 、dbusを介してシステムマネージャ(コンテナ内のPID 1)と通信します。マネージャーはgrep
を呼び出します 、その仕事をします。 grep
コマンドはstdoutに出力されます。stdoutは、 sudo
の元となる疑似端末に接続されています。 呼び出されました。
セキュリティ設定
ユーザーと動的ユーザー
さらに面倒なことはせずに、最も単純で最も強力なプリミティブから始めて、いくつかの特定の設定について話しましょう。
まず、最も古く、最も基本的で、おそらく最も有用な特権分離メカニズムであるユーザーです。 User =foobar
でユーザーを定義できます [サービス] ユニットファイルのセクション、または systemd-run -p User =foobar
、または systemd-run --uid =foobar
。当たり前のように思えるかもしれませんが、Androidでは、すべてのアプリケーションが独自のユーザーを取得しますが、Linuxの世界では、rootとして不必要に実行されるサービスが多すぎます。
Systemd
オンデマンドでユーザーを作成するメカニズムを提供します。 DynamicUser =yes
で呼び出された場合 、サービスには一意のユーザー番号が割り当てられます。この番号は一時的なユーザー名に解決されます。この割り当ては/etc / passwd
に保存されません 、ただし、番号または対応する名前が照会されるたびに、代わりにNSSモジュールによってオンザフライで生成されます。サービスが停止した後、その番号は後で別のサービスで再利用される可能性があります。
通常の静的ユーザーをサービスに使用する必要があるのはいつですか。また、動的ユーザーを使用するのはいつですか。動的ユーザーは、ユーザーIDが一時的なものであり、システム内の他のサービスとの統合が必要ない場合に最適です。ただし、データベースに特定のユーザーアクセス、特定のグループと共有されるディレクトリ、またはユーザー名を参照するその他の構成を許可するポリシーがある場合、動的ユーザーはおそらく最良のオプションではありません。
名前空間をマウントする
一般に、 systemd
に注意する必要があります 多くの場合、カーネルによって提供されるラッピング機能のみです。たとえば、ファイルシステムツリーへのアクセスを制限し、その一部を読み取り専用またはアクセス不能にするさまざまな設定は、非共有マウント名前空間に適切なファイルシステムを配置することで実現されます。
このようにいくつかの便利な設定が実装されています。最も便利で一般的な2つは、 ProtectHome =
です。 およびProtectSystem=
。 1つ目は、非共有マウント名前空間を使用して / home
を作成します 読み取り専用または完全にアクセスできない。 2つ目は、 / usr
の保護についてです。 、 / boot
、および / etc
。
3つ目も便利ですが、非常に具体的な設定は PrivateTmp =
です。 。マウント名前空間を使用して、プライベートディレクトリを / tmp
として表示します。 および/var / tmp
サービスのために。ファイル名の衝突や間違った権限による問題を回避するために、サービスの一時ファイルは他のユーザーから隠されています。
ファイルシステムビューは、 InaccessiblePaths =
を介して個々のディレクトリのレベルで管理できます。 、 ReadOnlyPaths =
、 ReadWritePaths =
、 BindPaths =
、および ReadOnlyBindPaths =
。最初の2つの設定は、ファイルシステム階層の一部へのすべてまたは書き込みアクセスを提供します。 3つ目は、アクセスの復元に関するものです。これは、階層の深い特定のディレクトリにのみフルアクセスを許可する場合に役立ちます。最後の2つでは、ディレクトリを移動できます。より正確に言えば、ディレクトリを別の場所にプライベートにバインドマウントできます。
DynamicUser =yes
の件名に戻ります 、このような一時的なユーザーは、サービスがディスク上に永続ファイルを作成することを許可されていない場合にのみ可能です。そのようなファイルが他のユーザーに表示された場合、所有者がいないと表示されるか、さらに悪いことに、同じ番号の新しい一時的なユーザーがファイルにアクセスして、情報漏えいや意図しない特権の昇格につながる可能性があります。 Systemd
マウント名前空間を使用して、ファイルシステムツリーの大部分をサービスに対して書き込み不可にします。永続的なストレージを許可するために、サービスに表示されるファイルシステムツリーにプライベートディレクトリがマウントされます。
これらの保護は、ファイルの所有権とアクセス許可マスクを使用した基本的なファイルアクセス制御メカニズムとは無関係であることに注意してください。ファイルシステムが読み取り専用でマウントされている場合、標準のアクセス許可に基づいて特定のファイルを変更できるユーザーでさえ、ファイルシステムが読み取り/書き込みで再マウントされるまで変更できません。これは、ファイル管理の誤りに対する保護手段を提供し(結局のところ、ユーザーが誤ったアクセス許可マスクを設定することは前例のないことではありません)、多層防御戦略のレイヤーです。
カーネルの実装が効率的であるため、マウント名前空間を使用して実装されたリソースは、一般的に非常に効率的です。それらを設定するときのオーバーヘッドも通常は無視できます。
サービスのディレクトリの自動作成
systemd
という比較的新しい機能 サービスを提供するのは、ディレクトリの自動管理です。ファイルシステムのパスが異なれば、ストレージの特性や使用目的も異なりますが、いくつかの標準的なカテゴリに分類されます。 FHSは、 / etc
を指定します 設定ファイル用です、 / var / cache
非永続ストレージ用です、 / var / lib /
半永久的なストレージ用です、 / var / log
ログの場合、および / run
揮発性ファイルの場合。多くの場合、サービスにはこれらの各場所にサブディレクトリが必要です。 Systemd
ConfigurationDirectory =
によって制御されるように、それを自動的に設定します 、 CacheDirectory =
、 StateDirectory =
、 LogsDirectory =
、および RuntimeDirectory =
設定。ユーザーはそれらのディレクトリを所有します。ランタイムディレクトリは、サービスが停止するとマネージャによって削除されます。一般的な考え方は、これらのファイルシステム資産の存在をサービスの存続期間に結び付けることです。事前に作成する必要はなく、サービスの実行が停止した後に適切にクリーンアップされます。
$ sudo systemd-run -t -p User=user -p CacheDirectory=foo -p StateDirectory=foo -p RuntimeDirectory=foo -p PrivateTmp=yes ls -ld /run/foo /var/cache/foo /var/lib/foo /etc/foo /tmp/
Running as unit: run-u45882.service
Press ^] three times within 1s to disconnect TTY.
drwxr-xr-x 2 user user 40 Apr 26 08:21 /run/foo ← automatically created and removed
drwxr-xr-x 2 user user 4096 Apr 26 08:20 /var/cache/foo ← automatically created
drwxr-xr-x. 2 user user 4096 Nov 13 21:50 /var/lib/foo ← automatically created
drwxr-xr-x. 2 root root 4096 Nov 13 21:50 /etc/foo ← automatically created, but not owned by the user, since the service (usually) shall not modify its own configuration
drwxrwxrwt 2 root root 40 Apr 26 08:21 /tmp/ ← "sticky bit" is set, but this directory is not the one everyone else sees
もちろん、これらの7つの場所( PrivateTmp =
を数える 2つとして)すべてのサービスのニーズをカバーするわけではありませんが、ほとんどの状況では十分なはずです。その他の場合は、手動セットアップまたは tmpfiles.d
での適切な構成 常にオプションです。
自動ディレクトリ管理は、 DynamicUser =
とうまく連携します 別のユーザーとして実行され、ファイルシステムツリーの大部分を変更することを許可されていないサービスを提供することにより、ユーザーを設定し、自動的に作成します(ファイルアクセス許可で許可されている場合でも)。サービスは、ユニットファイルの構成以外の設定を行わなくても、選択したディレクトリにアクセスしてデータを保存できます。
たとえば、PythonWebサービスは次のように実行されます。
$ systemd-run -p DynamicUser=yes -p ProtectHome=yes -p StateDirectory=webserver --working-directory=/srv/www/content python3 -m http.server 8000
または同等のユニットファイルを介して:
[Service]
DynamicUser=yes
ProtectHome=yes
StateDirectory=webserver
WorkingDirectory=/srv/www/content
ExecStart=python3 -m http.server 8000
ファイルシステムを変更したり、ユーザーデータにアクセスしたりすることなく、サービスが一時的なユーザーとして実行されるようにします。
ここで説明する設定は「高レベル」と見なすことができます。実装には注意が必要かもしれませんが、概念自体は簡単に理解でき、サービスへの影響は明らかです。さまざまな権限や機能を取り除いたり、ネットワークプロトコルやカーネルの調整可能機能をロックダウンしたり、個々のシステムコールを無効にしたりするために、他にも多数の設定があります。これらは、この短い記事の範囲外です。広範なリファレンスドキュメントを参照してください。
これらすべてを活用する
サービスの機能と必要性を十分に理解すると、必要な特権と取得できる特権を検討できます。明らかな候補者は非特権ユーザーとして実行されており、 / home
の下のユーザーデータへのアクセスを制限しています 。 systemd
を許可すればするほど 設定するため(たとえば、 StateDirectory =
を使用して) および友人)、サービスが非特権ユーザーとして正常に実行できる可能性が高くなります。多くの場合、サービスは特定のサブディレクトリにアクセスする必要があり、 ReadWritePaths =
を使用してそれを実現できます。 および同様の設定。
あらゆる種類の自動方法でセキュリティ対策を追加することは不可能です。さまざまな構成シナリオやさまざまな操作でサービスが何を必要としているかを十分に理解していないと、有用なサンドボックスを定義できません。これは、サービスのサンドボックス化は、作成者またはメンテナが行うのが最適であることを意味します。
評価と現状
可能な設定の数は多く、 systemd
のリリースごとに新しい設定が追加されます 。それに追いつくのは難しいです。 Systemd
ユニットファイルでのサンドボックスディレクティブの使用を評価するためのツールを提供します。結果はヒントと見なす必要があります。結局のところ、前述のように、セキュリティポリシーの自動作成は困難であり、評価では、特定のサービスにとって何が重要であるかを深く理解することなく、使用されているものと使用されていないものをカウントするだけです。
$ systemd-analyze security systemd-resolved.service
NAME DESCRIPTION EXPOSURE
...
✓ User=/DynamicUser= Service runs under a static non-root user identity
✗ DeviceAllow= Service has a device ACL with some special devices 0.1
✓ PrivateDevices= Service has no access to hardware devices
✓ PrivateMounts= Service cannot install system mounts
PrivateTmp= Service runs in special boot phase, option does not apply
✗ PrivateUsers= Service has access to other users 0.2
ProtectHome= Service runs in special boot phase, option does not apply
✓ ProtectKernelLogs= Service cannot read from or write to the kernel log ring buffer
✓ ProtectKernelModules= Service cannot load or read kernel modules
✓ ProtectKernelTunables= Service cannot alter kernel tunables (/proc/sys, …)
ProtectSystem= Service runs in special boot phase, option does not apply
✓ SupplementaryGroups= Service has no supplementary groups
...
→ Overall exposure level for systemd-resolved.service: 2.1 OK 🙂
$ systemd-analyze security httpd.service
NAME DESCRIPTION EXPOSURE
...
✗ User=/DynamicUser= Service runs as root user 0.4
✗ DeviceAllow= Service has no device ACL 0.2
✗ PrivateDevices= Service potentially has access to hardware devices 0.2
✓ PrivateMounts= Service cannot install system mounts
✓ PrivateTmp= Service has no access to other software's temporary files
✗ PrivateUsers= Service has access to other users 0.2
✗ ProtectHome= Service has full access to home directories 0.2
✗ ProtectKernelLogs= Service may read from or write to the kernel log ring buffer 0.2
✗ ProtectKernelModules= Service may load or read kernel modules 0.2
✗ ProtectKernelTunables= Service may alter kernel tunables 0.2
✗ ProtectSystem= Service has full access to the OS file hierarchy 0.2
SupplementaryGroups= Service runs as root, option does not matter
...
→ Overall exposure level for httpd.service: 9.2 UNSAFE 😨
繰り返しますが、これはサービスが安全でないことを意味するのではなく、 systemd
を使用していないことを意味します セキュリティプリミティブ。
分布全体のレベルを見る:
$ systemd-analyze security '*'
ほとんどのサービスのスコアが非常に高い(つまり、悪い)ことがわかります。さまざまな社内サービスに関するこのような統計を収集することはできませんが、類似していると想定するのは妥当なようです。確かに手に負えない果物はたくさんあり、比較的単純なサンドボックスを適用すると、システムがより安全になります。
まとめ
systemd
を許可する サービスの管理とサンドボックス化は、Linuxサーバーにセキュリティの層を追加するための優れた方法です。上記の構成をテストして、組織に何が役立つかを確認することを検討してください。
この記事では、ネットワーキングについての言及を慎重に避けました。これは、2回目の記事で、ネットワークを使用したサービスのソケットのアクティブ化とサンドボックス化について説明するためです。
[さらに役立つヒントについては、systemdのチートシートを確認することを忘れないでください。 ]