AL@のTech Blog

個人用備忘録

【rbash】SCP転送したいがSSH接続時はコマンドの実行を制限したい場合

タイトル通りですが、SCP転送させたいがSSH接続は制限するというちょっとワガママなことを実現させる方法になります。

目次

・要件
・ユーザーの作成
・鍵作成&設定
・rbashの設定
環境変数 $PATHの設定

要件

・SCP転送でファイルを送りたい
SSH接続(*1)されても、ある程度制限かけたい(*2)
・SCP転送用のユーザーを用意する
  SCP転送先&ホームディレクトリ:/opt/test-file

(*1)
SSH接続先でのコマンド実行方法としては以下の2パターンが考えられるので、どちらも制限したいと思います。

SSH接続後にSSH接続先のサーバでコマンドの実行
例)

[root@src-server ~]# ssh test-user@aaa.aaa.aaa.aaa
[test-user@dest-server ~]# ls

 
SSHコマンドと同時にSSH接続先でコマンドを実行する
例)

[root@src-server ~]# ssh test-user@aaa.aaa.aaa.aaa ls


(*2)
ある程度の制限とは、SSH接続先であるサーバ内のディレクトリやファイルを参照または変更できないことを言います。
例えば、ls,mv,rm,rmdirコマンドの実行禁止。

前提

・転送元サーバ、転送先
OS:CentOS7.9
Shell:bash
 

ユーザーの作成

SCP転送用のユーザー、グループを作成します。

ユーザー名:test-user
グループ名:test-group

[test-user@dest-server ~]# groupadd test-group
[test-user@dest-server ~]# grep test-group /etc/group
test-group:x:1002:

[test-user@dest-server ~]# useradd test-user -g 1002 -d /opt/test-file
[test-user@dest-server ~]# grep test-user /etc/passwd
test-user:x:2001:1002::/opt/test-file:/bin/bash

 
 

鍵作成&設定

test-user用の公開鍵と秘密鍵を作成します。

[test-user@dest-server ~]# ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/opt/test-file/.ssh/id_rsa):
Created directory '/opt/test-file/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /opt/test-file/.ssh/id_rsa.
Your public key has been saved in /opt/test-file/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:cqxkgcm6HyA8/fmD663EM+XyTXEy7hHxmmjSL7L0ujc test-user@dest-server
The key's randomart image is:
+---[RSA 2048]----+
|                 |
|   . o           |
|    + .  .       |
|. ..   o  o      |
|.oo.  +.S= o     |
| ..ooo=+o O      |
|  . .@o= *       |
|   .o+@E= .      |
|    oBO=++       |
+----[SHA256]-----+

 
  
公開鍵の名前は変更させ、パーミッションは600に変更してください。

[test-user@dest-server ~]# mv /opt/test-file/.ssh/id_rsa.pub /opt/test-file/.ssh/authorized_keys
[test-user@dest-server ~]# chmod 600 /opt/test-file/.ssh/authorized_keys

 
秘密鍵は転送元サーバの~/.ssh配下に格納してください。
 

rbashの設定

rbashを作成します。
rbashとは、制限機能付きシェルのことで、cdコマンドの実行等を制限してくれます。

rbashが制限できる機能の詳細は、以下のマニュアルにあります。
Man page of RBASH


 

[test-user@dest-server ~]# ln -s /bin/bash /bin/rbash
[test-user@dest-server ~]# ll /bin/ | grep bash
lrwxrwxrwx. 1 root root          9 Jan 28 14:36 rbash -> /bin/bash

 

test-userが実行するシェルをrbashに変更します。

[test-user@dest-server ~]# usermod -s /bin/rbash test-user
[test-user@dest-server ~]# grep test-user /etc/passwd
test-user:x:2001:1002::/opt/test-file:/bin/rbash

 
 

環境変数 $PATHの設定

現状の設定だとtest-userの実行シェルはrbashを指定していますが、test-userの./bash_profileで設定されている$PATHはデフォルトのままです。

仮にSSH接続した場合、rbashのシェルとして実行されるのでcdコマンドの実行は制限できます。
ただし$PATHの中身は変わっていないので、binディレクトリ配下などにあるコマンドが実行できてしまい、結果としてcdコマンド以外のコマンドは通常通り実行できてしまいます。
 
そのため、$PATHはscpコマンドしか実行できないよう、scpコマンドのシンボリックリンクが配置されているディレクトリを指定する必要があります。
 

[test-user@dest-server ~]# vim /opt/test-file/.bash_profile
PATH=$PATH:$HOME/.local/bin:$HOME/bin
↓
PATH=/opt/test-file

 
では、実際にSSH接続してコマンドの実行は制限できているか確認してみます。
  
 
まずはパターン①を実施します。
SSH接続後にSSH接続先のサーバでコマンドの実行

[root@src-server ~]# ls
-rbash: ls: command not found
[root@src-server ~]# cd
-rbash: cd: restricted

lsコマンドはコマンドの参照先(今回の場合では/opt/test-file配下)にlsコマンドの実行に必要なファイルが存在しないので、参照エラーとなっています。
cdコマンドはrbashで実行を制限しているので、「restriced」と表示されています。



次にパターン②を実施します。
SSHコマンドと同時にSSH接続先でコマンドを実行する

[root@src-server ~]# ssh test-user@192.168.2.32 ls -ls
total 0
0 -rw-r--r--. 1 root root 0 Jan 28 14:53 hoge

残念ながらrbashと$PATHを変更したにも関わらず、「ls -ls」コマンドが実行されてしまいました。。。


調べてみるとどうやら以下の仕様が原因のようです。
 
ssh(1) manページ

コマンド が指定されている場合は コマンド はログインシェルの代わりにリモートホスト上で実行されます。

 
Man page of BASH

bash は、リモートシェルデーモン rshd やセキュアシェルデーモン sshd によって実行された場合など、標準入力がネットワーク接続に接続された 状態で実行されたかどうかを調べます。 この方法によって実行されていると bash が判断した場合、 ~/.bashrc が存在し、かつ読み込み可能であれば、 bash はコマンドをこのファイルから読み込んで実行します。

 
 
先ほどパターン②で実行したSSHコマンドの「ls -ls」コマンドが実行できてしまうのは、
SSH接続時だが.pash_profileではなく、.bashrcファイルを実行しているため「/opt/test-file」ではないデフォルトの$PATHで実行されてしまうからのようです。
 
従ってパターン②のリモートコマンドの実行を制限するために、.bashrcファイルで$PATHを定義するように設定を変更します。また今回.bashrcで$PATHを定義するので、.bash_profileの$PATHはコメントアウトします。

[root@src-server ~]# vim /opt/test-file/.bash_profile
PATH=/opt/test-file
↓
#PATH=/opt/test-file
:wq
[root@src-server ~]# vim /opt/test-file/.bashrc
PATH=/opt/test-file
:wq

 
再度、パターン②を実行します。 
SSHコマンドと同時にSSH接続先でコマンドを実行する

[root@src-server ~]# ssh test-user@x ls -ls
rbash: ls: command not found

 
今度はちゃんと制限できましたね。
 
 
最後にSCP転送を試すと

[root@src-server ~]# scp ./source-file test-user@192.168.2.32:~
rbash: scp: command not found
lost connection

SCP転送が失敗しましたね。
先ほどscp転送先サーバであるtest-userのシェルはrbashで実行するように変更したせいか、scpコマンドはNGのようです。
 
 
なのでscpコマンドが実行できるようにscpファイルのシンボリックリンクを作成します。

[test-user@dest-server ~]# ln -s /bin/scp /opt/test-file/scp
[test-user@dest-server ~]# ls -l /opt/test-file/
lrwxrwxrwx. 1 root root 8 Jan 28 15:40 scp -> /bin/scp

再度SCP転送を試してみます。

[root@src-server ~]# scp -i id_rsa ./source-file  test-user@192.168.2.32:~
source-file                                                                        100%    0     0.0KB/s   00:00
 
[test-user@dest-server ~]# ls -l
-rw-r--r--. 1 test-user test-group 0 Jan 28 15:52 source-file

無事、SCP転送できました。
これで上記の要件はすべて満たせますね。
 
 
最後にこのままだと転送先サーバ上でSCPコマンドが実行できてしまうので、iptablesもしくはセキュリティグループでアウトバウンド側のSSH(デフォルトport22)は通信できないよう設定すれば問題ないかと思います。