前回のおさらい
前回の記事 で、Match の否定(!)は
- 正パターンに少なくとも1つ一致する
- 否定パターンには一致してはならない
という評価になる、という話を書きました。
この仕様をうまく使うと、同一属性内の疑似 AND 条件を作ることができます。
ついでに、Match が複数ヒットした場合の挙動(前方優先)にも触れておきます。
やりたいこと
例えばこういう要件です。
- Group が A の人には
hostAだけ許可 - Group が B の人には
hostBだけ許可 - A と B の両方に所属している人には両方許可
これを PermitOpen で書きたい。
これで書けたらいいのに...という例
例①
「PermitOpenを追加していけばいいよね!パターン」
PermitOpenの設定が追加されることを期待して、ABどちらにも所属している人はどちらにもマッチして追加されるだろうという書き方
Match Group A
AllowTcpForwarding yes
PermitOpen hostA
Match Group B
AllowTcpForwarding yes
PermitOpen hostB
例②
「列挙すればANDだよね!パターン」
Group A,Bで「AかつB」となってもらって後から上書きしたいパターン
Match Group A
AllowTcpForwarding yes
PermitOpen hostA
Match Group B
AllowTcpForwarding yes
PermitOpen hostB
Match Group A,B
AllowTcpForwarding yes
PermitOpen hostA
PermitOpen hostB
これらは期待通りに動きません。
②に関してはカンマ区切りの列挙はORなのでダメなわけですが、例①はうまくいきそうにも見えます。
これがうまく動かない理由は複数マッチ時の挙動にあります。
Match が複数ヒットした場合の挙動
ここも重要です。
sshd_config の Match は、
- 上から順番に評価され、先にマッチしたブロックの設定が適用される
という仕様です。
そして同じオプションが複数回設定された場合、
- 先に適用された値が有効になる
- 後続の設定は上書きされない
- 追記はされない
という挙動になります。
つまり、前に書いた方が強いという前方優先です。
そのため、例①の場合は、AB両方に所属している場合には追記はされず、最初にマッチする
Match Group A
AllowTcpForwarding yes
PermitOpen hostA
の設定のみが有効になります。
これらの仕様によって、
- A の人
- B の人
- A,B の人
を単純に3ブロックで分けるのは難しくなります。
否定を使って疑似 AND を作る
ここで否定の仕様を使います。
Match Group A,!B は
(Aに所属) AND (Bに所属しない)
でした。
これを利用します。
# Aだけの人
Match Group A,!B
AllowTcpForwarding yes
PermitOpen hostA
# Bだけの人
Match Group B,!A
AllowTcpForwarding yes
PermitOpen hostB
# AとB両方の人
Match Group A,B
AllowTcpForwarding yes
PermitOpen hostA
PermitOpen hostB
なぜこれでうまくいくのか
1. Aだけの人
-
Match Group A,!Bにマッチ -
Match Group B,!Aにはマッチしない -
Match Group A,Bにマッチ(しかし後方なので上書きされない)
→ hostA のみ許可
2. Bだけの人
-
Match Group A,!Bにはマッチしない -
Match Group B,!Aにマッチ -
Match Group A,Bにマッチ(しかし後方なので上書きされない)
→ hostB のみ許可
3. AとB両方の人
-
Match Group A,!B→ Bに所属しているのでマッチしない -
Match Group B,!A→ Aに所属しているのでマッチしない -
Match Group A,B→ マッチ
→ hostA と hostB 両方許可
つまり、
Aだけ
Bだけ
AかつB
を分離できています。
ポイント
- カンマは OR
- 否定は「一致してはいけない禁忌」
-
A,!BはA AND NOT B -
Matchは上から評価される(前方優先) - 条件の書き順が重要
まとめ
Match は一見すると単純な OR 条件の集合に見えますが、
- 否定は補助条件(禁忌)
- 複数マッチ時は前方優先
という少し癖のある仕様になっています。
「同一属性内の AND は書けない」と思われがちですが、
A,!B
B,!A
A,B
のように分解すれば、疑似的に実現できます。
設定が増えてくると意図しないマッチが発生しやすいほか、最終的に設定される値は設定の順番に大きく依存します。
書いたあとは必ずテストすることをおすすめしますし、メンテナンス性を考慮するとあまり多用するべきではない。ものだとは感じますが、使えない方法論ではないので共有しておきます。