From the blog

Azure Storage and SFTP via CLI

keyboard

I had a need to stand up an SFTP server in Azure. I found a blog post on Microsoft Docs that used an ARM template to set this up (https://docs.microsoft.com/en-us/samples/azure-samples/sftp-creation-template/sftp-on-azure/).

The basic steps I needed to accomplish were:

  1. Create an Azure Storage Account
  2. Create a File Share on the Azure Storage Account
  3. Stand up a Container Instance of the atmoz/sftp image and point it to the File Share

Note: I wanted to ultimately stand up an Azure Function that responds to files being added but Files Shares do not currently communicate with Event Bus like Blob Storage.

Additionally, I wanted to use Azure CLI instead of an ARM template to stand up the infrastructure. Here is the PowerShell script that I came up with:

# Set up variables
$storageAccountType = "Standard_LRS";
$storageAccountName = "";
$fileShareName = "";
$location = "eastus";
$resourceGroupName = "";
$containerGroupName = "";
$fileShareContainerName = "";
$ftpShareContainerName = "";
$sftpUserName = "";
$sftpPassword = "";
$sftpUsers = [string]::Concat($sftpUserName, ":", $sftpPassword, ":1001");

# Get or create storage account
$storage = az storage account show --resource-group $resourceGroupName --name $storageAccountName;
if ($storage -eq $null)
{
    $storageAccountName = az storage account create --resource-group $resourceGroupName --name $storageAccountName --location $location --kind StorageV2;
}

# Fetch the storage keys
$storageKeys = az storage account keys list --account-name $storageAccountName | ConvertFrom-Json;
$storageKey = $storageKeys[0].value;

# Get or create container
$container = az container show --resource-group $resourceGroupName --name $fileShareContainerName;
if ($container -eq $null) {
    $container = az container create --resource-group $resourceGroupName --name $fileShareContainerName --image "microsoft/azure-cli" --dns-name-label $fileShareContainerName --cpu 1.0 --memory 1.5 --os-type Linux --command-line "az storage share create --name $fileShareName" --environment-variables AZURE_STORAGE_KEY=$storageKey AZURE_STORAGE_ACCOUNT=$storageAccountName;
}
$container = az container show --resource-group $resourceGroupName --name $ftpShareContainerName;

if ($container -eq $null) {
    $container = az container create --resource-group $resourceGroupName --name $ftpShareContainerName --image "atmoz/sftp:latest" --dns-name-label $ftpShareContainerName --cpu 2 --memory 1 --os-type Linux --ports 22 --environment-variables SFTP_USERS=$sftpUsers --azure-file-volume-mount-path "/home/$sftpUserName/upload" --azure-file-volume-share-name $fileShareName --azure-file-volume-account-key $storageKey --azure-file-volume-account-name $storageAccountName --ip-address Public --protocol TCP
}

A note on the above script. It is a direct translation of the source ARM templates. One of the steps is to use a container to create a file share on the storage account. You will get an error if you try to run this directly in the CLI with no delay immediately after creating the storage account. My best guess is that there is a small delay needed between creating the storage account and creating a file share and the workaround was to spin up a container. You could also use a thread sleep to achieve the same since we are in PowerShell.