Samba の共有を 1 人のユーザーと 1 つの VPN アドレスに限定する
Samba の valid users と hosts allow は人とアドレスを組にしない。2 つの共有名でその組を表現でき、交差ペアのテストがそれを証明する。
この設計では、どのユーザーがディレクトリを使えるかという権限と、どのアドレスがそもそも接続できるかという権限という二つの別個の権限が混同されている。アカウントの一覧を接続元の一覧の隣に書くと組になっているように感じるが、Samba は二つの一覧を独立した述語として評価する。両方を満たす者は誰でも受け入れられ、それは大半の管理者が意図するより広い規則である。修正は、共有の構成を変えるか、組を表現できるポリシー層を用意することのどちらかである。
神話: 二つの一覧が一つの規則になる
smb.conf のリファレンスは valid users と hosts allow を無関係な二つのパラメーターとして定義しており、一つの共有に両方を設定したところから混乱が始まる。valid users = mira, tomas と hosts allow = 10.77.0.21, 10.77.0.22 を設定すると四つの組み合わせが受け入れられ、Mira はどちらのアドレスからでも、Tomas もどちらのアドレスからでも接続できる。設定の中で最初の名前を最初のアドレスに結び付けるものはなく、名前の並び順にも意味はない。順序を入れ替えても、二つ目の hosts allow 行を追加しても、一行に一名ずつ書いても何も変わらない。結果は二つの一覧の積であり、両者の対応付けではない。
多くの人が実際に望むのはもっと狭く、Mira は一つのアドレスからのみ、Tomas は別のアドレスからのみというものである。単一の共有定義にはその結び付けの構文がなく、どんなに工夫した順序でも作成できない。これは Samba が一つの共有の中では表現しないポリシーの形であり、そこで神話が生き残る。
Samba が評価するものとその順序
段階は決まった順序で進み、順序を誤ると診断も誤る。クライアントが接続を開き、設定されていればグローバルなホスト検査が走り、セッション設定がアカウントを認証し、その後にクライアントが共有へ接続してその共有独自のホスト一覧、valid users、読み取り専用の設定が適用され、ファイルを開いたときに初めて認証済み ID のファイルシステムのパーミッションが判断する。各段階は単独で要求を拒否でき、一つを通過しても次について何も語らない。重要な帰結は、共有のホスト一覧が評価される時点でアカウントは既に判明しており、ホスト一覧にはそのアカウントを名指す手段が依然としてないことである。
だからこそ共有は一人のユーザーを一つのアドレスに結び付けられず、hosts allow と valid users は同じツリー接続段階で適用される別々の述語であり、それぞれが自分の問いに答える。ホストの述語はアカウント名を入力として取らないため、ユーザーごとに書くことはできない。組を表現できるのは二つ目の共有か、Samba の外側のポリシー層だけである。
グローバル値が重要なのは継承のされ方による。hosts allow を省略した共有はグローバル値を継承し、独自の値を設定した共有はグローバル値の代わりにその値を使うのであり、追加ではない。したがって広いグローバル一覧は、パラメーターを決して設定しない共有を広げ、独自の値を定義した共有には何もしない。testparm -s を実行し、出力される共有ごとの値を読むべきである、というのは、その出力が実際に効いているポリシーであり、ディスク上のファイルではないからである。
一つの共有を狭めてもサーバーの残りには何の効果もない。他の共有、印刷キュー、IPC 接続はそれぞれの規則を保つため、一つの共有のアドレス一覧に頼る設計は一つの経路を守るだけで、ホストを守るわけではない。
一つのディレクトリに二つの共有名
同じディレクトリに二人の利用者が二つのアドレスから到達できる必要があるなら、別々の名前で二回公開する。各ブロックは一つのアカウントと一つの接続元を持ち、組を設定で強制できるものに変える。代償は、各利用者が同じファイルに到達するために別の共有名を使うことであり、それはクライアント側の意図的な変更でなければならない。
[shared-mira]
path = /srv/shared
guest ok = no
read only = yes
valid users = mira
hosts allow = 10.77.0.21
hosts deny = ALL
[shared-tomas]
path = /srv/shared
guest ok = no
read only = yes
valid users = tomas
hosts allow = 10.77.0.22
hosts deny = ALL
共有のゲートはファイルシステムのパーミッションではない。両方の ID は基盤となる ACL を通じてディレクトリへのアクセスを依然として必要とし、読み取り専用の設定は二層目であって唯一の層ではない。書き込みアクセスはワークフローが必要とする場合にのみ与え、その後、一方の ID が作成したファイルが他方にとっても使えるままであることを確認する。
両方のブロックが一つのパスを指すため、ディレクトリの変更は両方の共有に影響する。それは通常意図したことだが、パーミッションの誤りが二人の利用者に同時に見えることも意味する。
接続元アドレスが証明できること
Samba が見るアドレスはサーバーに届いたアドレスであり、クライアントが持っていると思っているアドレスではない。すべてのクライアントを一つの接続元アドレスに変換する VPN ゲートウェイはその区別を消し、すべてのクライアントが同じホストとして到着して接続元一覧はもはやそれらを区別できない。クライアントごとの安定した割り当てと接続元を保持するゲートウェイが、アドレスをポリシーとして使う前提条件である。どちらもなければ、制限は利用者ではなくゲートウェイを測ることになる。
それでも、アドレスはデバイスではない。一つのトンネルアドレスの背後にある二台のノート PC、再割り当てされたリース、共有されたワークステーションは、接続元が人を特定するという前提をいずれも崩す。制限はネットワークの範囲として扱い、認証済みの SMB アカウントを ID 層として維持するべきであり、デバイスの承認が必要なら証明書のようなデバイスの資格情報を併用する。
設計がサーバーではなく共有を閉じるのも同じ理由である。拒否された組でもセッションを開き、別の共有に到達し、サーバーを一覧できるが、これは接続時の認証失敗とは異なる結果である。認証の前に拒否することが要件なら、Samba の共有パラメーターは適切な道具ではない。
交差ペアで証明する
設定を検証したうえで、再利用したセッションではなく新しい接続で四つの組み合わせを試す。意図した組はディレクトリに到達し、二つの交差ペアはいずれも失敗するはずである。以前のテストのキャッシュされたセッションは誤った組み合わせにも平然と応答し、壊れた規則を正しく見せてしまう。
testparm -s
smbclient //fileserver/shared-mira -U mira -c 'ls'
smbclient //fileserver/shared-tomas -U tomas -c 'ls'
smbstatus --shares
構文検査はファイルが解析できることを示すだけである。認証情報、ACL、ホストの判断は実際の接続で試されるため、テストしたいアドレスからクライアントのコマンドを実行し、どの段階で拒否されるかを観察する。交差ペアが成功するなら、実際に効いているホスト一覧はブロックが示すより広く、testparm -s が最初に読むべきものである。交差ペアが誤った理由で失敗するなら、アカウントか ACL が疑わしい。
smbstatus でセッションを監視して終了させるのは、アクセスが始まった後の対応であり、入場制御ではない。観測されたアドレス全体を遮断すると、同じ NAT の背後の無関係な利用者も切断しうるため、判断は共有の定義に、監視は対応プロセスに属する。両者を分けておけば、設計は何を強制しているかについて正直であり続ける。