負荷分散等でサーバを複数台使うことが増えて lsyncd を使うことが増えた。lsyncd は rsh
セクションで使用する秘密鍵を自由に指定出来るのでセキュリティの観点から一般ユーザでデータのやり取りをするのが良いのだけど同期先に root で接続しなければならないことがある。
というのは複数のユーザがファイルやディレクトリを作成する環境だとファイルやディレクトリの Owner、Group がそれぞれのものになる。これを一般ユーザ(例えば lsyncd
)でログイン、コピーしようとすると lsyncd の設定で archive = true
や owner = true
、group = true
を設定していても Owner はすべて lsyncd
となる。同期先の環境ではパーミッションは変更出来ても所有者を変更する権限が無いので所有者を維持したまま同期したければ root
を使わざるを得ない。(ローカルの lsyncd
自体は root
で動く)
ネット上には lsyncd の設定で一般で同期させるために rsh = "ssh -i /home/lsyncd/.ssh/id_rsa"
のような設定をする方法をあまり見かけないのでそもそも一般ユーザで同期させようとする方が特殊なのかもしれない。
ということで lsyncd と rsync を root で同期するけどなるべくセキュリティを高めたいなということで考えてみる。lsyncd 自体に設定をすることは出来ないの SSH の方をなんとかする。
Match ブロックで接続元を制限する
SSH サーバには Match
ブロックで条件付をすることが出来るようになっている。この条件には IP アドレスなどを指定することが出来るのでこれを利用して root
でログイン可能なホストを絞り込む。詳しくは man sshd_config
を見れば書いてあるのだけどだいたいこんな感じで書くことが出来る。複数指定する場合にカンマの間にスペースなどを入れてはならない。サンプルとして PermitRootLogin yes
と書いているが lsyncd を使用する場合はパスワード認証が使えないので必然的に prohibit-password
(without-password
)を使うことになるだろう。
PermitRootLogin no Match Address 10.0.0.1 PermitRootLogin yes Match Address 10.0.0.2,10.0.0.3 PermitRootLogin prohibit-password Match Address 172.16.0.0/16 LocalPort 10022 PermitRootLogin prohibit-password
Match
ブロックは次の Match
ブロックが出現するまでがひとつのブロックになっている。IP などの指定は IP アドレス以外にネットワークアドレスを指定したり複数指定することが出来る。Address
以外にも指定可能なものがいくつかあり、 LocalPort
などを使えば「パブリックな 22 番ポートへのアクセスはブロック、ファイヤーウォール側の 10022 番ポートへのアクセスは許可」という設定も出来る。
The available criteria are User, Group, Host, LocalAddress, LocalPort, and Address.
設定したあとは必ず確認しておいた方がいい。特に IP アドレスで制限を設ける場合。正しく設定したつもりがすべての条件に一致しなくて二度と SSH 接続出来なくなるなんてこともある。(実際 Qiita にそういう人が居た)
確認方法は sshd -T
だけど、OpenSSH のバージョンによって動作が異なるっぽい。
CentOS 8
sshd -T
Mach Address
が使われている場合は addr
が必要になる。
'Match Address' in configuration but 'addr' not in connection test specification.
addr
の指定方法は下記の通り。
sshd -T -C addr=10.0.0.1
sshd -T
で普通にテスト結果が出力される。connection_spec を指定して実行してみるとどうなるか。
sshd -T -C addr=10.0.0.1
user, host and addr are all required when testing Match configs
上記の通り CentOS 8 とは挙動が違うらしく、user
、host
、addr
のすべての指定が必要になる。少し長くなって面倒だが下記のように指定する。
ssh -T -C user=root,host=localhost,addr=10.0.0.1
これで結果が出力されるのであとは | grep permitroot
なんかで見やすいように絞り込む。
sshd_config
で接続元を絞り込んでも許可されているホストからは秘密鍵を持っていれば接続してコマンドを実行出来てしまう(万が一のときに役に立つかもしれないが)。そこで、authorized_keys
のオプションを使って端末の割り当てやエージェント転送などをさせないようにする。restrict
は OpenSSH 7.2 以降に追加された機能で、初期の Amazon Linux では恐らく OpenSSH 6.6 (2013) くらいなので対応しておらず、無効なオプションになり公開鍵も無効になってしまうので注意が必要。OpenSSH のバージョンが古い場合はパッケージを更新した方がいいだろう。なお、この機能は SSH サーバ側の機能である。
no-pty,no-port-forwarding,no-agent-forwarding,no-X11-forwarding ssh-rsa XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX lsyncd # OpenSSH 7.2 以降 であれば ``restrict'' でまとめることが出来る restrict ssh-rsa XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX lsyncd
これで root
でログインされてもシェルは使えないようになる。
なお、ユーザに端末を割り当てない方法としてはユーザのログインシェルに /usr/sbin/nologin
や /usr/bin/false
を使う方法があるが、これは SSH 接続が確立出来ないので lsyncd では使えない。
authorized_keys で接続元を制限する
/etc/ssh/sshd_config
にあまり変更を加えたくないという場合もあるかと思う。また、Amazon Linux の場合は最初から PermitRootLogin yes
になっているのでそもそも Match
ブロックを使う必要が無い(PermitRootLogin no
に変更するなら話は別だが)。
authorized_keys
には上記のように端末の割り当てなどを禁止する他に、接続元を制限するオプションもある。
AUTHORIZED_KEYS FILE FORMAT from="pattern-list" Specifies that in addition to public key authentication, either the canonical name of the remote host or its IP address must be present in the comma-separated list of patterns. See PATTERNS in ssh_config(5) for more information on patterns. In addition to the wildcard matching that may be applied to host- names or addresses, a from stanza may match IP addresses using CIDR address/masklen notation. The purpose of this option is to optionally increase security: public key authentication by itself does not trust the network or name servers or anything (but the key); however, if somebody somehow steals the key, the key permits an intruder to log in from anywhere in the world. This additional option makes using a stolen key more difficult (name servers and/or routers would have to be compromised in addition to just the key).
PATTERNS A pattern consists of zero or more non-whitespace characters, `*' (a wildcard that matches zero or more characters), or `?' (a wildcard that matches exactly one character). For example, to specify a set of decla- rations for any host in the ".co.uk" set of domains, the following pat- tern could be used: Host *.co.uk The following pattern would match any host in the 192.168.0.[0-9] network range: Host 192.168.0.? A pattern-list is a comma-separated list of patterns. Patterns within pattern-lists may be negated by preceding them with an exclamation mark (`!'). For example, to allow a key to be used from anywhere within an organization except from the "dialup" pool, the following entry (in authorized_keys) could be used: from="!*.dialup.example.com,*.example.com" Note that a negated match will never produce a positive result by itself. For example, attempting to match "host3" against the following pattern- list will fail: from="!host1,!host2" The solution here is to include a term that will yield a positive match, such as a wildcard: from="!host1,!host2,*"
注意しなければならないのは例の最後にあるが、否定条件のみ指定した場合はすべて拒否することになるため上記の example.com
の例のように許可するものを追加しておく必要がある。
アドレスには単一の IP アドレス以外にワイルドカードと CIDR(IPアドレス/マスク長
)も使える。[0-5]
などのレンジの指定は出来ず、10.0.0.0/255.255.255.0
のような記述は誤り。記述が誤っていてもエラーメッセージは「ブロックされています」などではなく単に「公開鍵エラー」となるだけなので制限が正しく効いているか確認するのは大事。
from="10.0.0.1",restrict ssh-rsa XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX lsyncd from="10.0.0.*",restrict ssh-rsa XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX lsyncd from="10.0.?.*",restrict ssh-rsa XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX lsyncd from="10.0.1?.*",restrict ssh-rsa XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX lsyncd from="10.0.0.0/24",restrict ssh-rsa XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX lsyncd
なお、コンフィグで PermitRootLogin no
になっている場合は authorized_keys
で from
設定してもログインは出来ない。