scpの隠しオプション(-t / -f)で転送するファイルを制御してみる。


# 特定のファイルだけを落とす仕組みを即席で用意したかった。

クラウドサーバー上の特定のファイルをダウンロードすることしか出来ないようにする仕組みとして、scpの隠しオプション(`-f`)を利用する方法を久しぶりに設定した。

他にもなんかしら自動化の用途とかで利用する機会があるかもしれないので
- `-t`: ローカルからリモートへ転送する際の転送先ディレクトリを指定して制御
- `-f`: リモートからローカルへ転送するファイルを指定して制御
  - ディレクトリ指定の場合は追加で再帰コピー(`-r`)のオプションが必要

を利用した設定と動作確認結果を残す。

:::note info
これらのオプションは実際のコマンド実行で利用することを想定していないため、リファレンスマニュアル(`man scp`)には載っていない。
:::

:::note info
OpenSSHのソースコードによると`-d`という隠しオプションも存在するようだが、ここでは触れない。
:::

# 鍵ファイルを用意する。

`ssh-keygen -t ed25519 -C scpOptionTest -f ~/.ssh/scpOptionTestKey -N ''`

ここでは挙動確認のためだけに使うのでパスフレーズ無し(`-N ''`)で作成する。
リモート側へ設定する公開鍵は scpOptionTestKey.pub で出力される。

```~/.ssh/scpOptionTestKey.pub
ssh-ed25519 AAAA...
```

# `-t`: ローカルからリモートへ転送する際の転送先ディレクトリを指定して制御する

ローカルの任意のファイルをリモートの特定ディレクトリへ転送するように制御する設定。
（アップロード先のディレクトリを固定化する。）

## ~/.ssh/authorized_keysの仕込み

作成した公開鍵を設定する。その際に実行可能なコマンドとして
`command="scp -t /var/tmp/"`を設定する。
こうすることでリモートの`/var/tmp`ディレクトリに転送される。

他にも禁止事項を設定しておく(`no-agent-forwarding,no-port-forwarding,no-pty`)

```config:authorized_keys
command="scp -t /var/tmp/",no-agent-forwarding,no-port-forwarding,no-pty ssh-ed25519 AAAA... scpOptionTest
```

## 用意したファイル

リモートに転送するファイル

```local.txt
LOCAL FILE
```

## scpコマンドを試す

### 1. local.txtを転送する。

```bash
scp -i ~/.ssh/scpOptionTestKey \
  ./local.txt remote_user@12.34.56.78:./
```

実行結果: `/var/tmp`直下に転送される。

```bash
# ls /var/tmp/
local.txt

# cat /var/tmp/local.txt
LOCAL FILE
```

### 2. リモートの別ディレクトリへ転送してみる。

```bash
scp -i ~/.ssh/scpOptionTestKey \
  ./local.txt remote_user@12.34.56.78:/home/remote_user/
```

実行結果: 指定したディレクトリではなく`/var/tmp`ディレクトリに転送される。

```bash
# ls /home/remote_user/
(local.txtがない)

# ls /var/tmp/
local.txt

# cat /var/tmp/local.txt
LOCAL FILE
```

### 3. リモートから転送するコマンドを実行してみる。

```bash
scp -i ~/.ssh/scpOptionTestKey \
  remote_user@12.34.56.78:/var/tmp/remote.txt ./
```

実行結果: コマンドが返ってこなかったので Ctrl+C で強制終了。ファイルも転送されていなかった。

```bash
# ls /var/tmp/
(local.txtがない)
```

## ファイル名で指定することも可能

ファイル名まで指定すると、リモートへ転送したファイルは指定したファイル名で保存される。

```config:authorized_keys
command="scp -t /var/tmp/local_to_remote.txt",no-agent-forwarding,no-port-forwarding,no-pty ssh-ed25519 AAAA... scpOptionTest
```

# `-f`: リモートからローカルへ転送するファイルを指定して制御する

リモートの特定ファイルだけをローカルに転送するように制御する場合の設定。
（ダウンロードするファイルを固定化する。）

## ~/.ssh/authorized_keysの仕込み

実行可能なコマンドとして
`command="scp -f /var/tmp/remote.txt"`を設定する。
こうすることでリモートの`/var/tmp/remote.txt`ファイルのみ転送される。

```config:authorized_keys
command="scp -f /var/tmp/remote.txt",no-agent-forwarding,no-port-forwarding,no-pty ssh-ed25519 AAAA... scpOptionTest
```

## 用意したファイル

ローカルに転送するファイル

```/var/tmp/remote.txt
REMOTE FILE
```

## scpコマンドを試す

### 1. remote.txtを転送する。

```bash
scp -i ~/.ssh/scpOptionTestKey \
  remote_user@12.34.56.78:./ ./
```

実行結果: `/var/tmp/remote.txt`が転送されてくる。

```bash
# ls ./
remote.txt

# cat remote.txt
REMOTE FILE
```

# 2. リモートの別ファイルを転送してみる。

```bash
scp -i ~/.ssh/scpOptionTestKey \
  remote_user@12.34.56.78:/var/tmp/local_to_remote.txt ./
```

実行結果: 指定したファイルではなく`/var/tmp/remote.txt`が転送されてくる。

```bash
# ls ./
remote.txt
(local_to_remote.txtがない)

# cat remote.txt
REMOTE FILE
```

# 3. ローカルから転送するコマンドを実行してみる。
```bash
scp -i ~/.ssh/scpOptionTestKey \
  ./local.txt remote_user@12.34.56.78:/var/tmp/
```

実行結果: コマンドが返ってこなかったので Ctrl+C で強制終了。ファイルも転送されてこなかった。

```bash
# ls ./
(remote.txtがない)
```

# 最後に
アップロード先の制御や、ダウンロードするファイルの制御くらいなら、しっかり時間をとって自前でWebとかのUIを作って運用するほうがホントは良いかもしれない。AWSで運用しているサーバーのログファイルであればCloudWatch Logsで閲覧できるようにしたりとか。

今回はそういうモノがすぐに用意できない中、即席でこの仕組みが要求される場面だったので多少面倒な手順ではあるものの役に立った。