# 10.4 Privilege separation, or privsep, is a method in OpenSSH by which operations that require root privilege are performed by a separate privileged monitor process. Its purpose is to prevent privilege escalation and mitigate attacks by: - reducing the privileged attack surface by performing most operations involving untrusted data in unprivileged code, - facilitating OS-level sandboxing of the components that are most exposed to attack, - reducing information-sharing between privileged and unprivileged code, and - containing attacks as much as possible to the unprivileged process, should they occur. 特権分離 (privilege separation、privsep) は、root 特権を必要とする操作を、 分離された特権を持つモニタプロセスによって実行する OpenSSH の手法です。 その目的は、以下によって特権昇格を防ぎ、攻撃を緩和することです。 - 信頼できないデータを扱うほとんどの操作を非特権コードで実行することで、 特権を持つ攻撃対象領域を削減する。 - 最も攻撃にさらされるコンポーネントの OS レベルでのサンドボックス化を 容易にする。 - 特権コードと非特権コードの間の情報共有を削減する。 - 万一攻撃が発生した場合に、それを可能な限り非特権プロセス内に封じ込める。 To achieve privilege separation in OpenSSH's sshd, the functions it performs are split across three discrete binaries: OpenSSH の sshd で特権分離を実現するために、sshd が実行する機能は 3 つの個別のバイナリに分割されています。 sshd is the main entry-point binary for the server. This binary retains privilege but performs a very limited set of tasks: loading and checking the configuration, listening for incoming connections and monitoring the status of connections through the pre-authentication phase of their lifecycle to implement the MaxStartups and PerSourcePenalties features. sshd は、サーバの主要なエントリポイントとなるバイナリです。このバイナリは 特権を保持しますが、実行するタスクはごく限られています。すなわち、設定の 読み込みとチェック、着信接続の待ち受け、そして MaxStartups と PerSourcePenalties の機能を実装するために、接続のライフサイクルの認証前 フェイズを通じて接続の状態を監視することです。 Apart from listening for and accepting connections, the sshd binary does not handle untrusted, network-derived data; instead it forks and executes the sshd-session binary for each new connection. 接続を待ち受けて受け入れることを除けば、sshd バイナリは信頼できない ネットワーク由来のデータを扱いません。代わりに、新しい接続ごとに sshd-session バイナリを fork して実行します。 +---------------------------------------------------------------+ | | | listening socket +-------------------+ | | \--------------+ sshd (listener) | | | +--------++---------+ | | || | | || fork+exec | | || | | +--------------++------------------+ | | | sshd-session (preauth monitor) | | | +--------------++------------------+ | | || | | || fork+exec | | || | | network socket +------------++--------------+ | | \-----------+ sshd-auth (unprivileged) | | | +------------++--------------+ | | | +---------------------------------------------------------------+ pre-authentication process structure (認証前のプロセス構造) sshd-session initially acts as the privileged monitor process for a connection before it completes authentication. During this phase, it does not deal directly with network-derived data, but forks and executes a third binary (sshd-auth, described next) to handle the SSH protocol communication over the network socket. sshd-session receives RPC messages from the sshd-auth subprocess when it needs to perform privileged operations, such as verifying an account's existence, signing with a host key, or checking a user's password. The monitor process implements a loose state machine that enforces the required structure and order of operations that sshd-auth may request. sshd-session は、接続が認証を完了する前は、当初その接続の特権を持つ モニタプロセスとして動作します。このフェイズの間、ネットワーク由来の データを直接扱うことはなく、ネットワークソケット上での SSH プロトコル通信を 処理するために 3 つ目のバイナリ (次に説明する sshd-auth) を fork して 実行します。sshd-session は、アカウントの存在確認、ホストキーによる署名、 ユーザーパスワードの確認など、特権を必要とする操作を実行する必要がある 場合に、sshd-auth サブプロセスから RPC メッセージを受け取ります。 モニタプロセスは、sshd-auth が要求しうる操作の必要な構造と順序を強制する、 緩やかな状態機械 (state machine) を実装しています。 sshd-auth is the network-facing process that implements the initial key agreement and authentication phase of the SSH protocol. It is started with privilege, but will sandbox and/or chroot(2) itself and drop privilege to an unprivileged account before processing any network traffic. All operations that require privilege, such as looking up user information, private key signatures, checking passwords, etc are performed by RPC to the parent sshd-session process. After authentication completes, sshd-auth serialises its SSH protocol and connection state, exports this to the parent sshd-session process and exits. sshd-auth は、SSH プロトコルの初期の鍵合意と認証フェイズを実装する、 ネットワークに面したプロセスです。特権を持って起動されますが、ネットワーク トラフィックを処理する前に、自身をサンドボックス化および/または chroot(2) し、 特権を非特権アカウントのものへと落とします。ユーザー情報の検索、秘密鍵による 署名、パスワードの確認など、特権を必要とするすべての操作は、親の sshd-session プロセスへの RPC によって実行されます。認証が完了すると、 sshd-auth は自身の SSH プロトコルと接続の状態をシリアライズし、これを親の sshd-session プロセスにエクスポートして終了します。 Communication between parent and child processes occurs over shared file descriptors. Parent processes also monitor their children for abnormal exit conditions, such as crashes or signalling via exit(3) status. These conditions are used in sshd to implement the PerSourcePenalties controls. 親プロセスと子プロセスの間の通信は、共有されたファイルディスクリプタ上で 行われます。親プロセスはまた、クラッシュや exit(3) ステータスによる シグナル通知など、子プロセスの異常終了の状態を監視します。これらの状態は、 sshd において PerSourcePenalties の制御を実装するために使用されます。 +---------------------------------------------------------------+ | | | +---------------++------------------+ | | | sshd-session (postauth monitor) | | | +---------------++------------------+ | | || | | || fork | | || | | network socket +--------------++---------------+ | | \-----------+ sshd-session (unprivileged) | | | +--------------++---------------+ | | | +---------------------------------------------------------------+ post-authentication process structure (認証後のプロセス構造) After authentication, sshd-session disconnects from its parent listener sshd (which doesn't track connections after authentication has succeeded) and forks again. The forked sshd-session child process will drop privilege to that of the authenticated user, import the previously-serialised connection state from sshd-auth and continue to perform network and SSH protocol operations for the remainder of the session. 認証後、sshd-session は親のリスナーである sshd (認証が成功した後は接続を 追跡しません) から切り離され、再び fork します。fork された sshd-session の 子プロセスは、特権を認証されたユーザーのものへと落とし、sshd-auth から 以前にシリアライズされた接続状態をインポートして、セッションの残りの間、 ネットワークと SSH プロトコルの操作を続けて実行します。 The parent sshd-session process continues to act as a privileged monitor process, performing actions that require privilege when requested via RPC. These operations include allocating PTYs and signing key re-exchange messages. 親の sshd-session プロセスは引き続き特権を持つモニタプロセスとして動作し、 RPC 経由で要求されたときに特権を必要とするアクションを実行します。これらの 操作には、PTY の割り当てや、鍵再交換メッセージへの署名が含まれます。 In portable OpenSSH several compile-time options affect privilege separation: portable OpenSSH では、いくつかのコンパイル時オプションが特権分離に 影響します。 --with-sandbox=style Controls the sandboxing implementation used by sshd-auth. OS level sandboxing is supported on a number of platforms. A fallback rlimit(2)-based sandbox provides some basic control on a wider set of platforms. Most supported sandboxes are detected and enabled automatically, so this option is mostly used to disable the sandbox (this is handy when debugging or running under tools like AddressSanitizer). sshd-auth が使用するサンドボックスの実装を制御します。OS レベルの サンドボックスは多数のプラットフォームでサポートされています。フォール バックの rlimit(2) ベースのサンドボックスは、より広範なプラットフォームで 基本的な制御を提供します。サポートされているほとんどのサンドボックスは 自動的に検出されて有効になるため、このオプションは主にサンドボックスを 無効にするために使用されます (これはデバッグ時や AddressSanitizer のような ツールの下で実行する際に便利です)。 --with-privsep-user=user Specifies the unprivileged user that sshd-auth will switch to before it starts handling untrusted data. This user must not be shared with any other system service, should own no files, should have a locked password, a shell that denies access (such as /bin/nologin or /bin/false) and the home directory set to the privilege separation path. For most platforms the default user is "sshd". sshd-auth が信頼できないデータの処理を開始する前に切り替える非特権 ユーザーを指定します。このユーザーは他のいかなるシステムサービスとも 共有してはならず、ファイルを所有すべきではなく、ロックされたパスワードと、 アクセスを拒否するシェル (/bin/nologin や /bin/false など)、そして特権分離 パスに設定されたホームディレクトリを持つべきです。ほとんどのプラット フォームでのデフォルトのユーザーは "sshd" です。 --with-privsep-path=/path Controls the directory that sshd-auth will chroot(2) to before dropping privileges. This directory should be empty, not shared with other system accounts and not readable or writable by the sandbox user. The default privsep path is "/var/empty". sshd-auth が特権を落とす前に chroot(2) するディレクトリを制御します。この ディレクトリは空であるべきで、他のシステムアカウントと共有されず、 サンドボックスユーザーが読み書きできないようにすべきです。デフォルトの privsep パスは "/var/empty" です。 You should do something like the following to prepare the privsep preauth environment: privsep の認証前環境を準備するには、次のような操作をする必要があります。 # mkdir /var/empty # chown root:sys /var/empty # chmod 755 /var/empty # groupadd sshd # useradd -g sshd -c 'sshd privsep' -d /var/empty -s /bin/false sshd On some platforms, only the pre-authentication part of privsep is supported, and the post-authentication part is disabled due to lack of support from the operating system. 一部のプラットフォームでは、privsep の認証前の部分のみがサポートされ、 認証後の部分はオペレーティングシステムのサポートがないため無効になります。 This is an example process list for a connection in the pre-authentication phase: これは認証前フェイズにある接続のプロセスリストの例です。 PID PPID UID CMD 1436 1 0 sshd: /usr/sbin/sshd -D [listener] 1 of 10-100 startups 47077 1436 0 sshd-session: djm [priv] 47078 47077 107 sshd-auth: djm [net] Where process 1436 is the listener, 47077 is the privileged sshd-session monitor process and 47078 is the unprivileged, network-facing sshd-auth process. ここで、プロセス 1436 はリスナー、47077 は特権を持つ sshd-session モニタ プロセス、47078 は非特権でネットワークに面した sshd-auth プロセスです。 And in the post-authentication phase: そして認証後フェイズでは、以下のようになります。 PID PPID UID CMD 47077 1436 0 sshd-session: djm [priv] 47091 47077 1000 sshd-session: djm@pts/1 47092 47091 1000 -bash Where process 47077 continues its role as a privileged monitor, 47091 is the user-privileged network-facing post-authentication process and 47092 is the user shell started for the session. ここで、プロセス 47077 は引き続き特権を持つモニタとしての役割を果たし、 47091 はユーザー特権でネットワークに面した認証後プロセス、47092 は セッションのために起動されたユーザーシェルです。