|||||||||||||||||||||

なんぶ電子

- 更新: 

opensshサブシステムのSFTP

SFTP

以前、vsftpを利用してFTPSサーバーを構築しました。

FTPS(File Transfer Protocol over SSL/TLS)とは別のセキュアなFTPの形態としてSFTP(SSH File Transfer Protocol)というものもあります。

こちらはSSHを通してFTP通信を暗号化するもので、Debianではopensshのサブシステムとしてもその機能が用意されています。

そこで今回はそれを用いたSFTPサーバーを構築していきたいと思います。

ポートの確認

SSHはデフォルトで22番ポートを用います。SFTPはリモートシェルとして使う22番ポートと共用することはできますが、パブリックなサーバーを設定する場合はアタックの多い22番ポートは避けるケースもあります。

その場合サーバーのポートの空きを確認する必要があります。

netstat等でも確認できますが、ここではlsofコマンドを使ってポートの空き状況を確認します。

lsofは本来オープンしているファイルをリストするコマンドですが、Linuxではポート(ネットワークソケット)もファイルとして扱われます。

iオプションで、インターネットアドレスにマッチするファイルを指定しています。もしIPv4だけを表示したい場合は、-i4 や逆にIPv6だけを表示したい場合は -i6として利用する事も可能です。

Pオプションを使えば、結果においてポート番号を名称に変換するのを防止できます(たとえば、ポートの80番がhttpと表示されるのを防止します)。 同様にnオプションはアドレスをホスト名に変換するのを防ぎます。これによりhostsファイルを参照しなくなるのでわずかだと思いますが負荷軽減が望めます。

開いているポートは、(LISTEN)というフラグが付与されますので、それをgrepの対象として絞り込みを行っています。

lsof -i -P -n | grep LISTEN
...
vsftpd  175732     root    3u  IPv4  996456      0t0  TCP *:21 (LISTEN)
apache2 175739     root    4u  IPv6  996477      0t0  TCP *:443 (LISTEN)

lsofの出力内容を簡単に説明すると次のようになります。

  • COMMAND

    コマンド

  • PID

    プロセスID

  • USER
  • FD

    ファイルディスクリプタです。

    これらの値は、cwd(Current Working Directory)、rtd(Root directory)、txt(Program text :コードとデータの両方)、mem(Memory-mapped file)、数値、に分かれます。

    数字の場合は、開いているファイルを指すディスクリプタ番号です。また末尾にuがついていたら読み取り/書き込みモードで開かれていることを示します。

  • TYPE

    リストされたファイルのタイプです。

    • REG(通常ファイル)
    • DIR(デイレクトリ)
    • CHR(キャラクタデバイスファイル)

      /dev/ttyS0などのデバイスファイルで、データを非同期で、順次的にバイトストリームとして読み書きします。

    • BLK(ブロックデバイスファイル)

      /dev/sdaなどのデバイスファイルで、データを固定長のブロック単位で読み書きします。ランダムアクセスが可能です。

    • FIFO(名前付きパイプ)

      名前付きパイプはプロセス間通信(IPC)で用いられるもので、パイプ同様にデータを流しこむことができます。

      シェルではコマンド同士を | で連結することでデータを流しこむことができますが、名前付きパイプでは事前に設定した名前(のファイル)に対して、一方が書き込み、もう一方が読み込みを行うことができます。

      ; パイプの作成
      $ mkfifo /tmp/test-pipe
      
      ; パイプを読み込み用に開く
      $ cat /tmp/test-pipe
      

      送信側として別のシェルを起動し次のように操作すると、パイプを読み込み用に開いたプロンプトに入力した文字が表示されます。

      ; パイプを書き込みとして開く
      $ cat > /tmp/test-pipe
      
      ; データの送信
      hello!
      

      通常のファイルではないので名前付きパイプに出力した文字列は受信後に消えます。

    • SOCK(ソケット)

      ソケットもIPCで用いられるものですが、名前付きパイプとの違いのひとつとして、双方向をサポートしている点があります。(名前付きパイプを使って双方向通信をする場合は受信と送信ふたつのパイプが必要)

    • IPv4(IPv4ソケット)
    • IPv6(IPv6ソケット)
  • DEVICE

    ファイルが存在するデバイスのメジャー+マイナーナンバーです。

  • SIZE/OFF

    ファイルのサイズかオフセットです。通常のファイルはサイズが、ソケットにはオフセット値が入ります(ソケットバッファ内のデータオフセット)。

  • NODE

    ファイルのinode番号です。

  • NAME

    ファイルやディレクトリ、ドメインソケットの場合はパスが、ネットワークソケットの場合は、アドレスとポート(対になることも)、が表示されます。

SFTPの設定とテスト接続

前述のように、ssh(openssh-server)がインストール済みとして、同梱のサブシステムを利用していきます。

Debianでは、sshの設定ファイルは、/etc/ssh/sshd_config にあります。デフォルトでSubsystem sftpは有効になっていると思いますが、念のため次の記述があるか確認します。

sshd_config

Subsystem       sftp    /usr/lib/openssh/sftp-server

新たに行を書き加える必要があった場合は、「 systemctl restart sshd 」とします。リモート接続していると接続が途切れることがあるかもしれませんので注意してください。

SFTPは通常ポート22番で稼働します。なので、sshシェルを利用しているようなら、他に設定しなくてもシェルのユーザーIDとパスワードでSFTPサーバーにアクセスできるようになっていることが多いです。

SFTPクライアントについては、Debianだけでなく、Windowsでもオプション機能のOpenSSHを有効にすれば、sftpコマンドが利用できます。次のようにしてSFTPサーバーへログインすることができます。

sftp user@192.168.1.1

ちなみにSFTPはFTPという名前がついていますが、通常のFTPのようにふたつのセッション(通信と制御)を持たないため、パッシブやアクティブといった概念はありません。また、同時接続にも対応しているので複数のポートを用意する必要もありません。さらに、バイナリとテキスト(アスキー)の概念もなく常にバイナリモードで転送が行われます。

SFTPのセキュリティ設定

前述のような理由で、公開ポートを変更します。デフォルトの22番を消してしまうと不具合が起きやすいので、22番はファイアウォールでローカル環境からのアクセスのみに制限し、かわりにパブリックで待ち受けるポートを別に設定します。ここでは2222番を使います。

既存のPort設定の次の行に新たな待ち受けポート2222を追加します。

sshd_config

...
Port 22
Port 2222
...

設定ファイルの最後にユーザー毎の設定を入れます。Match User ユーザー名で、特定のユーザーに対するsshの設定を記述することができます。まとめて記述したい場合は、「 Match Group グループ名 」というグループ指定も利用可能です。

sshd_config

Match User ftp
   X11Forwarding no
   AllowTcpForwarding no
   PermitTTY no
   ChrootDirectory %h
   ForceCommand internal-sftp
   PasswordAuthentication yes

ここでの設定値は次のような意味です。

  • X11Forwarding no

    X11(GUI画面)の転送を禁止します。

  • AllowTcpForwarding no

    SSHトンネリングを無効にします。

  • PermitTTY no

    ユーザーがTTYを割り当てることを禁止します。この設定は ForceCommand internal-sftp を設定する場合は不要ですが、noにしておくとsshで接続後にシェルに移行することができません。

  • ChrootDirectory %h

    %hがユーザーホームを指し、結果としてユーザーホームにchrootします。

    この時ユーザーホーム(より上位)の所有権はrootである必要があり、書き込み権限は外す必要があります。書き込みが必要な場合は、FTPユーザーに対して書き込みを許可したサブディレクトリを生成する必要があります。

  • ForceCommand internal-sftp

    Force Commandはユーザーログイン後に強制実行させるコマンドを指定する設定となります。sshd_conf はsshに関する設定ファイルなのでなにも設定しないとsshでのシェル接続を許可しますが、internal-sftp でそれを拒否しsftpのみに限定します。

    また先のPermitTTY yesと設定を共存させた場合、ログイン後に実行される ForceCommand internal-sftpが優先されます。

  • PasswordAuthentication yes

    パスワードによる認証を許可します。no の場合は公開鍵認証のみ許可されます。

以前のvsftpではバーチャルユーザーが利用可能でしたが、こちらの場合はそれができないようですので、Debianにログイン不可能なユーザーを作成します。

# useradd [ユーザー名] -g [グループ名] -d [ホーム] -s /usr/sbin/nologin
# passwd [ユーザー名]
...[FTP接続パスワード]

最後にsshdを再起動します。

/usr/sbin/nologin: No such file or directory

先の PermitTTY no と、ForceCommand internal-sftp はどちらもシェルへのログインを防ぐ設定がありますが、Debian OSへユーザー登録した -s /usr/sbin/nologin にもその効力があります。

これを設定しておくと PermitTTY no もForceCommand internal-sftpも設定していない場合でも、シェルログイン時に、「 This account is currently not available. 」というメッセージが出力されたとにsshが切断されます。

ただ、chroot環境を作っているとこのメッセージが「 /usr/sbin/nologin: No such file or directory 」というものに変わることがあります。

これは、chroot後のルートから探した /usr/sbin/nologin が存在しないから起きるメッセージで、いずれにしてもシェルにはログインできませんが、気になるのなら次のようにします。

  1. nologinバイナリのコピー

    chroot後のルートディレクトリを/var/chrootとします。

    chroot後もファイルが見つけられるようにバイナリをコピーします。

    # cp /usr/sbin/nologin /var/chroot/usr/sbin/nologin
  2. バイナリが依存するライブラリのコピー

    lddコマンドを使ってバイナリが依存するライブラリを調べます。

    # ldd /usr/sbin/nologin
     linux-vdso.so.1 
     libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 
     /lib64/ld-linux-x86-64.so.2 
    

    ライブラリも同様にパスが同じになるようにコピーします。

    # cp /usr/lib64/ld-linux-x86-64.so.2 /var/chroot/usr/lib64/ld-linux-x86-64.so.2
    # cp /lib/x86_64-linux-gnu/libc.so.6 /var/chroot/usr/lib/x86_64-linux-gnu/libc.so.6
    
  3. 起動の確認

    chroot環境でnologinが使えるか確認します。

    # chroot /var/chroot /usr/sbin/nologin
    This account is currently not available.
    

公開鍵認証の設定

公開鍵認証をする場合もSSHと同じ手法です。

まず、クライアント側で、秘密鍵と公開鍵のペアを作成します。コマンドの実行はSFTP接続をするユーザーで行うようにすると楽です。

$ ssh-keygen

既に鍵のセットが既存の場合は次のようなメッセージが出ます。既存のシステムが鍵のペアを利用している可能性が高いので上書きしないのが無難です。

/id_rsa already exists.
Overwrite (y/n)? n

既存の鍵のセットを使うこともできますが、どこで使用されているかわからない鍵のペアを使用するのが気になるようなら、-f オプションを使ってファイルパスを指定して新たに作成します。

$ssh-geygen -f ~/.ssh/key_for_ftp

通常の鍵のセットは id_rsa と id_rsa.pub ですが、この時の鍵のセットは key_for_ftp と key_for_ftp.pubとなります。.pubの表記がある方が公開鍵です。

つぎに、作成した公開鍵を、SFTPサーバーにコピーします。コピー先は [SFTP接続時に使うユーザーのホームディレクトリ]/.ssh/authorized_keys です。基本的にクライアント側の公開鍵の中身を目的のファイルにアペンド出力をすればいいのですが、次のコマンドをクライアント側から実行することでも可能です。

ssh-copy-id -i ~/.ssh/id_rsa.pub(作成した公開鍵) [SFTP接続時のユーザー名]@[SFTPサーバーアドレスorドメイン] 

ssh-copy-idはssh接続で処理されますので、SSHのポートを変更している場合は -p オプションとポートを指定してください。

これで公開鍵認証の設定は完了です。

クライアントからサーバーへ接続時は、sftpコマンドの-iオプションで秘密鍵へのパスを指定します。

sftp -i ~/.ssh/key_for_ftp [ユーザー名]@[サーバーアドレスorドメイン]

こちらのコマンドでポートを変更する場合は-P(大文字)オプションで指定します。

ログレベルの変更とファシリティの変更

FTPのログのレベルとファシリティは、sshd_confの Subsystemエントリー部分で指定します。

Subsystem sftp /usr/lib/openssh/sftp-server -l VERBOSE -f LOCAL7

-l オプションででログレベル、-f オプションでファシリティを指定します。

ログレベルはQUIET、FATAL、ERROR、INFO、VERBOSE、DEBUG、DEBUG1、DEBUG2、DEBUG3と存在し、デフォルトはERRORです。

ファシリティはsyslogにおけるそれに順じます。rsyslogなどの設定でファシリティによる区別を使って、SFTPのログをSSHのログと切り分けることもできます。

journalctlを使っている場合は、_COMM=sftp-server とするか、--facility=数値としてファシリティを指定する事で対象を絞り込むことができます。

# journalctl _COMM=sftp-server
  
# journalctl --facility=23

_COMMでは列と値を指定して絞り込んでいます。--facilityはファシリティを指定するオプションです。

journalctlにどのような列があるかは、ログによって違います。「 journalctl -o json-pretty 」とコマンド入力するとJSON形式でログが出力されるので、そのキー値が参考となると思います。

たとえば、_COMM のほかに SYSLOG_FACILITY という列もあるので --facilityは SYSLOG_FACILITY に置き換えることもできます。

--facilityはコマンドのオプションで、数値でファシリティを指定します。

数値とファシリティのマッピングは次のようになっているそうです。

  • 0: kern - カーネルメッセージ
  • 1: user - ユーザーレベルメッセージ
  • 2: mail - メールシステム
  • 3: daemon - システムデーモン
  • 4: auth - セキュリティ/認証メッセージ
  • 5: syslog - 内部的なsyslogdメッセージ
  • 6: lpr - 印刷サブシステム
  • 7: news - ニュースサブシステム
  • 8: uucp - UUCPサブシステム
  • 9: clock (または cron) - クロックデーモン
  • 10: authpriv - セキュリティ/認証メッセージ
  • 11: ftp - FTPデーモン
  • 12: ntp - NTPサブシステム
  • 13: security (または logaudit) -
  • 14: logalert - ログアラート
  • 15: clock (または cron2) - 2番目のクロックデーモン
  • 16 ~ 23: local0 から local7

記事の執筆にあたりchatGPTの回答を参考にしています。原則、得られた回答に対し自身で検証をした上で記述していますが、一部鵜呑みにしていたりする部分もございます。ご容赦ください。

筆者紹介


自分の写真
がーふぁ、とか、ふぃんてっく、とか世の中すっかりハイテクになってしまいました。プログラムのコーディングに触れることもある筆者ですが、自分の作業は硯と筆で文字をかいているみたいな古臭いものだと思っています。 今やこんな風にブログを書くことすらAIにとって代わられそうなほど技術は進んでいます。 生活やビジネスでPCを活用しようとするとき、そんな第一線の技術と比べてしまうとやる気が失せてしまいがちですが、おいしいお惣菜をネットで注文できる時代でも、手作りの味はすたれていません。 提示されたもの(アプリ)に自分を合わせるのでなく、自分の活動にあったアプリを作る。それがPC活用の基本なんじゃなかと思います。 そんな意見に同調していただける方向けにLinuxのDebianOSをはじめとした基本無料のアプリの使い方を紹介できたらなと考えています。

広告