Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
4b56ab5
init managed sftp prototype
jneprz Dec 20, 2024
5bb558b
port fix
jneprz Jun 23, 2025
d009ae2
more unit tests
jneprz Jun 25, 2025
a00eb0b
test fixes
jneprz Jun 25, 2025
0f3404f
clean tests
jneprz Jun 25, 2025
9e780c4
big clean
jneprz Jun 25, 2025
98f8f31
fix flake8
jneprz Jun 27, 2025
3572501
pylint fixes
jneprz Jun 27, 2025
5e63f71
fix versioning and summary
jneprz Jun 30, 2025
d63fcfc
simplify
jneprz Jun 30, 2025
8f47823
sftp cert ests
jneprz Jun 30, 2025
d6abb4a
sftp connect tests
jneprz Jun 30, 2025
7965a68
organize tests
jneprz Jun 30, 2025
ad0c14e
support tilde
jneprz Jul 1, 2025
26965f2
clean logged out logs
jneprz Jul 2, 2025
a3afc40
az sftp cert expiration
jneprz Jul 2, 2025
c41a733
az sftp cert argument combination tests
jneprz Jul 2, 2025
afd6be4
parameterize some tests
jneprz Jul 2, 2025
642c3f1
az sftp connect arg combos
jneprz Jul 2, 2025
be5aab0
remove batch mode
jneprz Jul 2, 2025
8a5ec03
unit tests
jneprz Jul 3, 2025
50f6b3e
simplify
jneprz Jul 3, 2025
009b832
update args and summary
jneprz Jul 3, 2025
6e72752
minor changes and add basic scenario tests
jneprz Jul 18, 2025
b6b1b40
style
jneprz Jul 18, 2025
5f24c22
remove validators
jneprz Jul 18, 2025
fff7bc3
remove connectivity utils and client factory
jneprz Jul 18, 2025
bc6f0c4
remove test-only functions
jneprz Jul 18, 2025
fd33fa2
remove unnecessary wrappers
jneprz Jul 18, 2025
7917a92
remove chmod
jneprz Jul 21, 2025
98656b8
remove batch commands example
jneprz Jul 21, 2025
17276b4
add sftp to service_name.json
jneprz Jul 22, 2025
7075b5c
Add copyright header test_sftp_scenario.py
calvinhzy Jul 28, 2025
0efd066
Update azext_metadata.json
calvinhzy Jul 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/service_name.json
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,11 @@
"AzureServiceName": "Virtual Machines",
"URL": "https://learn.microsoft.com/azure/virtual-machines/shared-image-galleries"
},
{
"Command": "az sftp",
"AzureServiceName": "Storage",
"URL": "https://learn.microsoft.com/en-us/azure/storage/blobs/secure-file-transfer-protocol-support"
},
{
"Command": "az spatial-anchors-account",
"AzureServiceName": "Mixed Reality",
Expand Down
8 changes: 8 additions & 0 deletions src/sftp/HISTORY.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.. :changelog:

Release History
===============

1.0.0b1
+++++++
* Initial preview release with SFTP connection and certificate generation support.
6 changes: 6 additions & 0 deletions src/sftp/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Azure CLI SFTP Commands
========================

Secure connections to Azure Storage via SFTP with SSH certificates.

Commands include certificate generation and SFTP connection management.
52 changes: 52 additions & 0 deletions src/sftp/azext_sftp/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

"""
Azure CLI SFTP Extension

This extension provides secure SFTP connectivity to Azure Storage Accounts
with automatic Azure AD authentication and certificate management.

Key Features:
- Fully managed SSH certificate generation using Azure AD
- Support for existing SSH keys and certificates
- Interactive and batch SFTP operations
- Automatic credential cleanup for security
- Integration with Azure Storage SFTP endpoints

Commands:
- az sftp cert: Generate SSH certificates for SFTP authentication
- az sftp connect: Connect to Azure Storage Account via SFTP
"""

from azure.cli.core import AzCommandsLoader

from azext_sftp._help import helps # pylint: disable=unused-import


class SftpCommandsLoader(AzCommandsLoader):
"""Command loader for the SFTP extension."""

def __init__(self, cli_ctx=None):
from azure.cli.core.commands import CliCommandType

super().__init__(
cli_ctx=cli_ctx,
custom_command_type=CliCommandType(
operations_tmpl='azext_sftp.custom#{}'))

def load_command_table(self, args):
"""Load the command table for SFTP commands."""
from azext_sftp.commands import load_command_table
load_command_table(self, args)
return self.command_table

def load_arguments(self, command):
"""Load arguments for SFTP commands."""
from azext_sftp._params import load_arguments
load_arguments(self, command)


COMMAND_LOADER_CLS = SftpCommandsLoader
98 changes: 98 additions & 0 deletions src/sftp/azext_sftp/_help.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# coding=utf-8
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

from knack.help_files import helps # pylint: disable=unused-import


helps['sftp'] = """
type: group
short-summary: Generate SSH certificates and access Azure Storage blob data via SFTP
long-summary: |
These commands allow you to generate certificates and connect to Azure Storage Accounts using SFTP.

PREREQUISITES:
- Azure Storage Account with SFTP enabled
- Appropriate RBAC permissions (Storage Blob Data Contributor or similar)
- Azure CLI authentication (az login)
- Network connectivity to Azure Storage endpoints

The SFTP extension provides two main capabilities:
1. Certificate generation using Azure AD authentication (similar to 'az ssh cert')
2. Fully managed SFTP connections to Azure Storage with automatic credential handling

AUTHENTICATION MODES:
- Fully managed: No credentials needed - automatically generates SSH certificate
- Certificate-based: Use existing SSH certificate file
- Key-based: Use SSH public/private key pair (generates certificate automatically)

This extension closely follows the patterns established by the SSH extension.
"""

helps['sftp cert'] = """
type: command
short-summary: Generate SSH certificate for SFTP authentication
long-summary: |
Generate an SSH certificate that can be used for authenticating to Azure Storage SFTP endpoints.
This uses Azure AD authentication to generate a certificate similar to 'az ssh cert'.

CERTIFICATE NAMING:
- Generated certificates have '-aadcert.pub' suffix (e.g., id_rsa-aadcert.pub)
- Certificates are valid for a limited time (typically 1 hour)
- Private keys are generated with 'id_rsa' name when key pair is created

The certificate can be used with 'az sftp connect' or with standard SFTP clients.
examples:
- name: Generate a certificate using an existing public key
text: az sftp cert --public-key-file ~/.ssh/id_rsa.pub --file ~/my_cert.pub
- name: Generate a certificate and create a new key pair in the same directory
text: az sftp cert --file ~/my_cert.pub
- name: Generate a certificate with custom SSH client folder
text: az sftp cert --file ~/my_cert.pub --ssh-client-folder "C:\\Program Files\\OpenSSH"
"""

helps['sftp connect'] = """
type: command
short-summary: Access Azure Storage blob data via SFTP
long-summary: |
Establish an SFTP connection to an Azure Storage Account.

AUTHENTICATION MODES:
1. Fully managed (RECOMMENDED): Run without credentials - automatically generates SSH certificate
and establishes connection. Credentials are cleaned up after use.

2. Certificate-based: Use existing SSH certificate file. Certificate must be generated with
'az sftp cert' or compatible with Azure AD authentication.

3. Key-based: Provide SSH keys - command will generate certificate automatically from your keys.

CONNECTION DETAILS:
- Username format: {storage-account}.{azure-username}
- Port: Uses SSH default (typically 22) unless specified with --port
- Endpoints resolved automatically based on Azure cloud environment:
* Azure Public: {storage-account}.blob.core.windows.net
* Azure China: {storage-account}.blob.core.chinacloudapi.cn
* Azure Government: {storage-account}.blob.core.usgovcloudapi.net

SECURITY:
- Generated credentials are automatically cleaned up after connection
- Temporary files stored in secure temporary directories
- OpenSSH handles certificate validation during connection
examples:
- name: Connect with automatic certificate generation (fully managed - RECOMMENDED)
text: az sftp connect --storage-account mystorageaccount
- name: Connect to storage account with existing certificate
text: az sftp connect --storage-account mystorageaccount --certificate-file ~/my_cert.pub
- name: Connect with existing SSH key pair
text: az sftp connect --storage-account mystorageaccount --public-key-file ~/.ssh/id_rsa.pub --private-key-file ~/.ssh/id_rsa
- name: Connect with custom port
text: az sftp connect --storage-account mystorageaccount --port 2222
- name: Connect with additional SFTP arguments for debugging
text: az sftp connect --storage-account mystorageaccount --sftp-args="-v"
- name: Connect with custom SSH client folder (Windows)
text: az sftp connect --storage-account mystorageaccount --ssh-client-folder "C:\\Program Files\\OpenSSH"
- name: Connect with custom connection timeout
text: az sftp connect --storage-account mystorageaccount --sftp-args="-o ConnectTimeout=30"
"""
42 changes: 42 additions & 0 deletions src/sftp/azext_sftp/_params.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
# pylint: disable=line-too-long


def load_arguments(self, _):

with self.argument_context('sftp cert') as c:
c.argument('cert_path', options_list=['--file', '-f'],
help='The file path to write the SSH cert to, defaults to public key path with -aadcert.pub appended')
c.argument('public_key_file', options_list=['--public-key-file', '-p'],
help='The RSA public key file path. If not provided, '
'generated key pair is stored in the same directory as --file.')
c.argument('ssh_client_folder', options_list=['--ssh-client-folder'],
help='Folder path that contains ssh executables (ssh-keygen, ssh). '
'Default to ssh executables in your PATH or C:\\Windows\\System32\\OpenSSH on Windows.')

with self.argument_context('sftp connect') as c:
c.argument('storage_account', options_list=['--storage-account', '-s'],
help='Azure Storage Account name for SFTP connection. Must have SFTP enabled.')
c.argument('port', options_list=['--port'],
help='SFTP port. If not specified, uses SSH default port (typically 22).',
type=int)
c.argument('cert_file', options_list=['--certificate-file', '-c'],
help='Path to SSH certificate file for authentication. '
'Must be generated with "az sftp cert" or compatible Azure AD certificate. '
'If not provided, certificate will be generated automatically.')
c.argument('private_key_file', options_list=['--private-key-file', '-i'],
help='Path to RSA private key file. If provided without certificate, '
'a certificate will be generated automatically from this key.')
c.argument('public_key_file', options_list=['--public-key-file', '-p'],
help='Path to RSA public key file. If provided without certificate, '
'a certificate will be generated automatically from this key.')
c.argument('sftp_args', options_list=['--sftp-args'],
help='Additional arguments to pass to the SFTP client. '
'Example: "-v" for verbose output, "-b batchfile.txt" for batch commands, '
'"-o ConnectTimeout=30" for custom timeout.')
c.argument('ssh_client_folder', options_list=['--ssh-client-folder'],
help='Path to folder containing SSH client executables (ssh, sftp, ssh-keygen). '
'Default: Uses executables from PATH or C:\\Windows\\System32\\OpenSSH on Windows.')
4 changes: 4 additions & 0 deletions src/sftp/azext_sftp/azext_metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"azext.isPreview": true,
"azext.minCliCoreVersion": "2.75.0"
}
13 changes: 13 additions & 0 deletions src/sftp/azext_sftp/commands.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

"""Command definitions for the Azure CLI SFTP extension."""


def load_command_table(self, _):
"""Load command table for SFTP extension."""
with self.command_group('sftp') as g:
g.custom_command('cert', 'sftp_cert')
g.custom_command('connect', 'sftp_connect')
37 changes: 37 additions & 0 deletions src/sftp/azext_sftp/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

from colorama import Fore, Style

# File system constants
WINDOWS_INVALID_FOLDERNAME_CHARS = "\\/*:<>?\"|"

# Default ports
DEFAULT_SSH_PORT = DEFAULT_SFTP_PORT = AZURE_STORAGE_SFTP_PORT = 22

# SSH/SFTP client configuration
SSH_CONNECT_TIMEOUT = 30
SSH_SERVER_ALIVE_INTERVAL = 60
SSH_SERVER_ALIVE_COUNT_MAX = 3

# Certificate and key file naming
SSH_PRIVATE_KEY_NAME = "id_rsa"
SSH_PUBLIC_KEY_NAME = "id_rsa.pub"
SSH_CERT_SUFFIX = "-aadcert.pub"

# Error messages and recommendations
RECOMMENDATION_SSH_CLIENT_NOT_FOUND = (
Fore.YELLOW +
"Ensure OpenSSH is installed correctly.\n"
"Alternatively, use --ssh-client-folder to provide OpenSSH folder path." +
Style.RESET_ALL
)

RECOMMENDATION_STORAGE_ACCOUNT_SFTP = (
Fore.YELLOW +
"Ensure your Azure Storage Account has SFTP enabled.\n"
"Verify your account permissions include Storage Blob Data Contributor or similar." +
Style.RESET_ALL
)
Loading
Loading