はじめに
sshd_config の Match ディレクティブで否定(!)を使ったとき、
「あれ?」となってこんがらがったので、sshd_configの否定条件について整理しておきます。
やりたかったこと
例えばこういう設定(これは動かない)。
Match Group !admin
ForceCommand /bin/false
これは、
-
adminグループに属していないユーザーを拒否する
設定のように見えます。
「!admin」、つまり「admin以外」に対しての条件を設定しているので、うまく設定できていそうですが......
残念ながらこれは通りません。
Match の否定以外の仕様の整理
Match の引数は「カンマ区切りのパターンリスト」です。
たとえば、否定を含まない場合には、Groupの例だと
Match Group A, B, C
のようになります。この場合、カンマで列挙したグループは OR 条件で繋いだ扱いで、この場合だと
(Aに所属) OR (Bに所属) OR (Cに所属)
という扱いになります。
ちなみに、同一の属性内でAND条件を扱うことは素直な方法ではできません(否定をうまく利用すると可能、別途記事作成予定)。
一方、他の属性と組み合わさると、それはANDとして扱われます。つまり、
Match Group A Address 192.168.1.1
は、
(Aに所属) AND (192.168.1.1からの接続)
となります。
ちなみに
Match Group A Group B
のように同一属性を列挙はできないので、「AにもBにも所属」はこのようには書けません。
Match の否定の仕様の整理
一方で、否定の条件の扱いは少し異なります。
Matchの否定条件を含めた判定の内部ロジックは概念的に
- 正のパターンに少なくとも1つ一致する
- 否定パターンには一致しない
となっていて、つまり、
Match Group A,!B
は
(A に所属) AND (B に所属しない)
です。つまり、「Aに所属していて、かつBには所属していない」となります。
ここでは、同じカンマ区切りでも OR ではありません。
否定条件も一般的な条件と同じように扱われるならば、上記の条件は
(A に所属) OR (B に所属しない)
となり、「Aに所属しているか、もしくはBに所属していない」になるべきですが、そうはなりません。
つまり、否定パターンは、「一致しないのはOK」ではなく、「絶対に一致してはいけない禁忌」として扱われるということになります。
なぜ !admin だけではダメなのか?
さて、上記の仕様を含めてもう一度最初の条件を見てみましょう。
Match Group !admin
これは期待通りに動きませんね。
理由は単純で、
- 少なくとも1つの「正パターン」に一致する必要がある
という仕様だからです。
!admin しかない場合、正パターンが存在せず、何にもマッチしません。「adminは絶対に排除する」という禁忌だけが設定されているわけです。
解決: *,!admin と書く
Match Group *,!admin
とすることで、
-
*で全ユーザーに一致させる(ダミー正パターン) -
!adminで admin を除外する
つまり、
(全員) AND (adminではない)
を作ることでようやく、
-
adminグループに属していないユーザーを拒否する
を設定できます。
公式ドキュメントは?
説明は man sshd_config に、
The patterns may include negation patterns, which are indicated by a ‘!’ prefix.
とだけ書いてあります。曖昧ですね......。
まとめ
Match の否定は:
-
!pattern単独では機能しない - 正パターンが最低1つ必要
- 評価は
(正パターン一致) AND (否定パターン非一致)
という仕様です。
「否定条件を書いたつもりなのに効かない」というハマりどころなので、
「否定条件はあくまで禁忌であって一致条件ではない」
と覚えておくとよさげです。