パブリックプレビューの SFTP support for Azure Blob Storage を AzureCLI で試してみた

## 背景と目的

外部システムと大きなサイズのデータを受け渡す際に SFTP を使うことがあります。これまでは自前で仮想マシンやコンテナーインスタンスを用意して SFTP 環境を用意する必要がありましたが、これで簡単に安く SFTP 環境を用意することが出来るようになります。

## 前提条件

コマンドの実施環境は、Mac + Azure CLI です。

```bash
$ sw_vers
ProductName:    macOS
ProductVersion: 12.0.1
BuildVersion:   21A559

$ az version
{
  "azure-cli": "2.30.0",
  "azure-cli-core": "2.30.0",
  "azure-cli-telemetry": "1.0.6",
  "extensions": {}
}
```

## SFTP support for Azure Blob Storage プレビュー機能を登録

```bash
# プレビュー機能を登録します
az feature register \
  --name AllowSFTP \
  --namespace Microsoft.Storage

# プレビュー機能を伝播します
az provider register \
  --namespace Microsoft.Storage

# State が Registering から Registered になるまで待ちます（自分の環境では20分くらいかかった）
az feature list \
  --query "[?contains(name, 'Microsoft.Storage/AllowSFTP')].{Name:name,State:properties.state}" \
  --output table
```

## storage-preview エクステンションを Azure CLI に追加

```bash
az extension add \
  --name storage-preview
```

エクステンションの追加後は、このようになりました。

```bash
az version
{
  "azure-cli": "2.30.0",
  "azure-cli-core": "2.30.0",
  "azure-cli-telemetry": "1.0.6",
  "extensions": {
    "storage-preview": "0.7.4"
  }
}
```

## Azure Blob Storage を作成

プレビューが利用可能なリージョンに日本が含まれていないため、東アジアリージョンを使用しました。

https://docs.microsoft.com/en-us/azure/storage/blobs/secure-file-transfer-protocol-support#regional-availability

また、前提条件に階層名前空間機能を有効にする必要がありました。

https://docs.microsoft.com/ja-jp/azure/storage/blobs/secure-file-transfer-protocol-support-how-to#prerequisites

```bash
# 環境変数をセットします
region=eastasia
prefix=presftp
subscid=$(az account show --query id --output tsv)

# リソースグループを作成します
az group create \
  --name ${prefix}-rg \
  --location $region

# Azure Blob Storage を作成します（汎用v2で階層名前空間を有効）
az storage account create \
  --name ${prefix}stor \
  --resource-group ${prefix}-rg \
  --sku Standard_LRS \
  --kind StorageV2 \
  --enable-hierarchical-namespace true
```

## SFTP を有効にして SFTP アカウントを作成

AzureCLI コマンドがまだ用意されていないようなので、AzureCLI から REST API を使用しました。

```bash
# SFTP を有効にします
az rest \
  --method patch \
  --url "https://management.azure.com/subscriptions/${subscid}/resourceGroups/${prefix}-rg/providers/Microsoft.Storage/storageAccounts/${prefix}stor?api-version=2021-08-01" \
  --body '{"properties": {"isSftpEnabled": true}}'

# ストレージキーを取得します
storagekey=$(az storage account keys list \
  --account-name ${prefix}stor \
  --resource-group ${prefix}-rg \
  --query "[0].value" \
  --output tsv)

# コンテナーを作成します
az storage container create \
  --account-name ${prefix}stor \
  --account-key ${storagekey} \
  --name sftpcontainer

# ディレクトリを作成します
az storage blob directory create \
  --container-name sftpcontainer \
  --directory-path ${prefix}user \
  --account-name ${prefix}stor \
  --account-key ${storagekey}

# SFTP アカウントを作成します（パスワード認証で全パーミッション付与）
# 出力されたパスワードをメモしておきます
az rest \
  --method put \
  --url "https://management.azure.com/subscriptions/${subscid}/resourceGroups/${prefix}-rg/providers/Microsoft.Storage/storageAccounts/${prefix}stor/localusers/${prefix}user?api-version=2021-08-01" \
  --body "
{
  \"properties\": {
    \"hasSshPassword\": true,
    \"hasSshKey\": false,
    \"permissionScopes\": [
      {
        \"resourceName\": \"sftpcontainer\",
        \"service\": \"blob\",
        \"permissions\": \"rwldc\"
      }
    ],
    \"homeDirectory\": \"sftpcontainer/${prefix}user\"
  }
}
" \
  --query "properties.sshPassword" \
  --output tsv

# PUT するファイルを作成します
date > date.txt

# SFTP 接続してファイルを PUT します
sftp ${prefix}stor.${prefix}user@${prefix}stor.blob.core.windows.net <<EOF
put date.txt
ls
quit
EOF
```

## （おまけ） IP アドレス制限をしてみます

```bash
# ネットワークのデフォルトを Deny にします
az storage account update \
  --name ${prefix}stor \
  --resource-group ${prefix}-rg \
  --default-action Deny

# SFTP 接続して先ほど PUT したファイルを確認します
sftp ${prefix}stor.${prefix}user@${prefix}stor.blob.core.windows.net <<EOF
ls
quit
EOF

# Permission denied となりました
Connected to ${prefix}stor.blob.core.windows.net.
sftp> ls
remote readdir("/${prefix}user/"): Permission denied
sftp> quit

# 自分の IP アドレスを許可します
az storage account network-rule add \
  --account-name ${prefix}stor \
  --resource-group ${prefix}-rg \
  --ip-address $(curl -s inet-ip.info)

# SFTP 接続して先ほど PUT したファイルを確認します
sftp ${prefix}stor.${prefix}user@${prefix}stor.blob.core.windows.net <<EOF
ls
quit
EOF

# ファイルが確認出来ました
Connected to ${prefix}stor.blob.core.windows.net.
sftp> ls
date.txt  
sftp> quit
```

## 参考

作成したリソースを削除します。

```bash
# リソースグループを削除します
az group delete \
  --name ${prefix}-rg
```

参考サイトです。

https://azure.microsoft.com/ja-jp/updates/sftp-support-for-azure-blob-storage-now-in-public-preview/

https://docs.microsoft.com/ja-jp/azure/storage/blobs/secure-file-transfer-protocol-support

https://docs.microsoft.com/ja-jp/azure/storage/blobs/secure-file-transfer-protocol-support-how-to