Skip to content

Commit 2a2d313

Browse files
Merge pull request #2 from normesta/patch-21
Fixing validation issues
2 parents 904b46c + 0d556e7 commit 2a2d313

2 files changed

Lines changed: 122 additions & 125 deletions

File tree

articles/storage/blobs/TOC.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ items:
233233
- name: Authorize access
234234
href: secure-file-transfer-protocol-support-authorize-access.md
235235
- name: Authorize access with Microsoft Entra ID (preview)
236-
href: secure-file-transfer-protocol-entra-id-based-access.md
236+
href: secure-file-transfer-protocol-support-entra-id-based-access.md
237237
- name: Connect from an SFTP client
238238
href: secure-file-transfer-protocol-support-connect.md
239239
- name: Performance considerations

articles/storage/blobs/secure-file-transfer-protocol-support-entra-id-based-access.md

Lines changed: 121 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ author: jeevanbalanmanoj
55
ms.date: 02/24/2026
66
ms.topic: how-to
77
ms.service: azure-blob-storage
8-
ms.date: 02/26/2026
98
ms.author: normesta
109
---
1110

@@ -68,10 +67,10 @@ Register the `SFTP Entra ID Support` preview feature on your Azure subscription.
6867

6968
Generate the OpenSSH certificate with the Azure CLI [az sftp](/cli/azure/sftp) command as shown in the following example.
7069

71-
```azurecli
72-
az login
73-
az sftp cert --file /my_cert.pub
74-
```
70+
```azurecli
71+
az login
72+
az sftp cert --file /my_cert.pub
73+
```
7574
For security reasons, the certificate is valid for only 65 minutes. After it expires, you need to rerun the command to get a new certificate.
7675

7776
> [!NOTE]
@@ -81,9 +80,9 @@ Optionally, you can generate your own SSH key pair and use it when downloading t
8180

8281
Generate SSH key pair: You must use RSA keys, as Microsoft Entra ID supports only RSA certificates.
8382

84-
```bash
85-
ssh-keygen -t rsa
86-
```
83+
```bash
84+
ssh-keygen -t rsa
85+
```
8786

8887
The following key files will be generated:
8988

@@ -94,127 +93,127 @@ The following key files will be generated:
9493

9594
Use the following command to generate the SSH certificate with the generated keys:
9695

97-
```azurecli
98-
az login
99-
az sftp cert --public-key-file /id_rsa.pub --file /my_cert.pub
100-
```
96+
```azurecli
97+
az login
98+
az sftp cert --public-key-file /id_rsa.pub --file /my_cert.pub
99+
```
101100

102101
If you're using a service principal, you can sign in by using either a client secret or a certificate:
103102

104103
To sign in by using a certificate, use the following command:
105104

106-
```azurecli
107-
az login --service-principal -u <application_id_or_client_id> --tenant <tenant_id> --certificate <path_to_certificate>
108-
```
105+
```azurecli
106+
az login --service-principal -u <application_id_or_client_id> --tenant <tenant_id> --certificate <path_to_certificate>
107+
```
109108

110109
To sign in by using a client secret, use the following command:
111110

112-
```azurecli
113-
az login --service-principal -u <application_id_or_client_id> -p <secret_value> --tenant <tenant_id>
114-
```
111+
```azurecli
112+
az login --service-principal -u <application_id_or_client_id> -p <secret_value> --tenant <tenant_id>
113+
```
115114

116115
After authentication, run the same command to download the certificate:
117116

118-
```azurecli
119-
az sftp cert --public-key-file /id_rsa.pub --file /my_cert.pub
120-
```
117+
```azurecli
118+
az sftp cert --public-key-file /id_rsa.pub --file /my_cert.pub
119+
```
121120

122121
#### [Azure PowerShell](#tab/azurepowershell)
123122

124123
Sign in to your Azure subscription with the `Connect-AzAccount` command and follow the on-screen directions. Service principals and managed identity authorization is not yet supported for generating a certificate.
125124

126-
```powershell
127-
Connect-AzAccount
128-
```
125+
```powershell
126+
Connect-AzAccount
127+
```
129128

130129
Generate the OpenSSH certificate by using [PowerShell Az.Sftp](https://www.powershellgallery.com/packages/Az.Sftp/0.1.0) as shown in the following example:
131130

132-
```powershell
133-
New-AzSftpCertificate -CertificatePath "\my_cert.cert"
134-
```
131+
```powershell
132+
New-AzSftpCertificate -CertificatePath "\my_cert.cert"
133+
```
135134

136135
Optionally, use the following command to generate the OpenSSH certificate by using your SSH keys:
137136

138-
```powershell
139-
New-AzSftpCertificate -PublicKeyFile "\id_rsa.pub" -CertificatePath "\my_cert.cert"
140-
```
137+
```powershell
138+
New-AzSftpCertificate -PublicKeyFile "\id_rsa.pub" -CertificatePath "\my_cert.cert"
139+
```
141140

142141
Learn more about the PowerShell module [here](/powershell/module/az.sftp/).
143142

144143
#### [.NET](#tab/dotnet)
145144

146-
```csharp
147-
148-
using Microsoft.Identity.Client;
149-
using Microsoft.Identity.Client.SSHCertificates;
150-
using Newtonsoft.Json;
151-
using System.Security.Cryptography;
152-
using System.Text;
153-
public class Program
145+
```csharp
146+
147+
using Microsoft.Identity.Client;
148+
using Microsoft.Identity.Client.SSHCertificates;
149+
using Newtonsoft.Json;
150+
using System.Security.Cryptography;
151+
using System.Text;
152+
public class Program
153+
{
154+
private const string AZURE_CLI_CLIENT_ID = "<your-azure-cli-client-id>";
155+
private const string MY_TENANT_ID = "<your-tenant-id>";
156+
public static async Task Main(string[] args)
154157
{
155-
private const string AZURE_CLI_CLIENT_ID = "<your-azure-cli-client-id>";
156-
private const string MY_TENANT_ID = "<your-tenant-id>";
157-
public static async Task Main(string[] args)
158+
var options = new PublicClientApplicationOptions
158159
{
159-
var options = new PublicClientApplicationOptions
160-
{
161-
ClientId = AZURE_CLI_CLIENT_ID,
162-
};
163-
var app = PublicClientApplicationBuilder.CreateWithApplicationOptions(options)
164-
.WithTenantId(MY_TENANT_ID)
165-
.WithDefaultRedirectUri()
166-
.Build();
167-
var scopes = new string[]
168-
{
169-
"`<https://pas.windows.net/CheckMyAccess/Linux/.default>`",
170-
};
171-
var keyId = new byte[32];
172-
Random.Shared.NextBytes(keyId);
173-
var rsa = RSA.Create();
174-
var key = rsa.ExportParameters(includePrivateParameters: true);
175-
if (key.Modulus == null || key.Exponent == null)
176-
throw new InvalidOperationException("RSA key generation failed: Modulus or Exponent is null.");
177-
var localKey = new
178-
{
179-
kty = "RSA",
180-
n = Convert.ToBase64String(key.Modulus).Replace("+", "-").Replace("/", "_"),
181-
e = Convert.ToBase64String(key.Exponent).Replace("+", "-").Replace("/", "_"),
182-
kid = BitConverter.ToString(keyId).Replace("-", string.Empty).ToLower(),
183-
};
184-
var localKeyJson = JsonConvert.SerializeObject(localKey);
185-
Console.WriteLine("RSA Key:");
186-
Console.WriteLine(localKeyJson);
187-
Console.WriteLine();
188-
189-
// Get SSH certificate
190-
191-
AuthenticationResult result = await app.AcquireTokenInteractive(scopes)
192-
.WithSSHCertificateAuthenticationScheme(localKeyJson, localKey.kid)
193-
.ExecuteAsync();
194-
195-
// Define output directory and certificate path
196-
197-
var sshDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".ssh", "entra");
198-
Directory.CreateDirectory(sshDir);
199-
var certPath = Path.Combine(sshDir, "id_rsa-cert.pub");
200-
201-
// Remove read-only attribute if certificate already exists so it can be overwritten
202-
203-
if (File.Exists(certPath))
204-
{
205-
File.SetAttributes(certPath, FileAttributes.Normal);
206-
}
207-
// Save the certificate
208-
var cert = `[$"[email protected]](mailto:$%[email protected])` {result.AccessToken}";
209-
await File.WriteAllTextAsync(certPath, cert);
210-
File.SetAttributes(certPath, FileAttributes.ReadOnly);
211-
// Dump certificate content to console
212-
Console.WriteLine("Cert");
213-
Console.WriteLine(cert);
214-
Console.WriteLine();
215-
}
216-
}
217-
```
160+
ClientId = AZURE_CLI_CLIENT_ID,
161+
};
162+
var app = PublicClientApplicationBuilder.CreateWithApplicationOptions(options)
163+
.WithTenantId(MY_TENANT_ID)
164+
.WithDefaultRedirectUri()
165+
.Build();
166+
var scopes = new string[]
167+
{
168+
"`<https://pas.windows.net/CheckMyAccess/Linux/.default>`",
169+
};
170+
var keyId = new byte[32];
171+
Random.Shared.NextBytes(keyId);
172+
var rsa = RSA.Create();
173+
var key = rsa.ExportParameters(includePrivateParameters: true);
174+
if (key.Modulus == null || key.Exponent == null)
175+
throw new InvalidOperationException("RSA key generation failed: Modulus or Exponent is null.");
176+
var localKey = new
177+
{
178+
kty = "RSA",
179+
n = Convert.ToBase64String(key.Modulus).Replace("+", "-").Replace("/", "_"),
180+
e = Convert.ToBase64String(key.Exponent).Replace("+", "-").Replace("/", "_"),
181+
kid = BitConverter.ToString(keyId).Replace("-", string.Empty).ToLower(),
182+
};
183+
var localKeyJson = JsonConvert.SerializeObject(localKey);
184+
Console.WriteLine("RSA Key:");
185+
Console.WriteLine(localKeyJson);
186+
Console.WriteLine();
187+
188+
// Get SSH certificate
189+
190+
AuthenticationResult result = await app.AcquireTokenInteractive(scopes)
191+
.WithSSHCertificateAuthenticationScheme(localKeyJson, localKey.kid)
192+
.ExecuteAsync();
193+
194+
// Define output directory and certificate path
195+
196+
var sshDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".ssh", "entra");
197+
Directory.CreateDirectory(sshDir);
198+
var certPath = Path.Combine(sshDir, "id_rsa-cert.pub");
199+
200+
// Remove read-only attribute if certificate already exists so it can be overwritten
201+
202+
if (File.Exists(certPath))
203+
{
204+
File.SetAttributes(certPath, FileAttributes.Normal);
205+
}
206+
// Save the certificate
207+
var cert = `[$"[email protected]](mailto:$%[email protected])` {result.AccessToken}";
208+
await File.WriteAllTextAsync(certPath, cert);
209+
File.SetAttributes(certPath, FileAttributes.ReadOnly);
210+
// Dump certificate content to console
211+
Console.WriteLine("Cert");
212+
Console.WriteLine(cert);
213+
Console.WriteLine();
214+
}
215+
}
216+
```
218217

219218
---
220219

@@ -234,11 +233,11 @@ For security reasons, the OpenSSH certificate is valid for 65 minutes. After thi
234233

235234
#### Connect by using an SFTP command
236235

237-
```bash
238-
C:\Users\username> sftp -o PubkeyAcceptedKeyTypes="[email protected],rsa-sha2-256" -o IdentityFile="C:\path\to\key\.ssh\id_rsa" -o CertificateFile="C:\path\to\cert\.ssh\my_cert.pub" storageaccountname.username@storageaccountname.blob.core.windows.net
239-
Connected to storageaccountname.blob.core.windows.net.
240-
sftp>
241-
```
236+
```bash
237+
C:\Users\username> sftp -o PubkeyAcceptedKeyTypes="[email protected],rsa-sha2-256" -o IdentityFile="C:\path\to\key\.ssh\id_rsa" -o CertificateFile="C:\path\to\cert\.ssh\my_cert.pub" storageaccountname.username@storageaccountname.blob.core.windows.net
238+
Connected to storageaccountname.blob.core.windows.net.
239+
sftp>
240+
```
242241

243242
If the principal uses the format [username@domain.com](mailto:username@domain.com), make sure to exclude the domain section in the command and use only the username portion.
244243

@@ -249,9 +248,9 @@ Both [User and service principals](/entra/identity-platform/app-objects-and-serv
249248

250249
Once connected, use the following command to upload a file to Azure Storage via SFTP:
251250

252-
```bash
253-
sftp> put 'C:\path\to\blob\blog.jpeg'
254-
```
251+
```bash
252+
sftp> put 'C:\path\to\blob\blog.jpeg'
253+
```
255254

256255
If you receive a permission denied error, ensure that you have the necessary Azure roles such as Storage Blob Data Contributor or Storage Blob Data Owner.
257256

@@ -277,38 +276,36 @@ SFTP clients such as WinSCP and PuTTY support OpenSSH-based authentication. The
277276

278277
Use the following command to connect by using the OpenSSH certificate obtained in the previous steps:
279278

280-
```azurecli
281-
az sftp connect --storage-account <<account_name>> --certificate-file /my_cert.pub
282-
```
279+
```azurecli
280+
az sftp connect --storage-account <<account_name>> --certificate-file /my_cert.pub
281+
```
283282

284283
Additionally, you can get the OpenSSH certificate and connect to SFTP by using a single command as follows:
285284

286-
```azurecli
287-
az sftp connect
288-
az sftp connect --storage-account <<account_name>>
289-
```
285+
```azurecli
286+
az sftp connect
287+
az sftp connect --storage-account <<account_name>>
288+
```
290289

291290
For more information about the commands, see [here](/cli/azure/sftp).
292291

293292
##### [Azure PowerShell](#tab/azurepowershell)
294293

295294
Use the following command to connect by using the OpenSSH certificate obtained in the previous steps:
296295

297-
```powershell
298-
Connect-AzSftp -StorageAccount "<<account_name>>" -CertificateFile "/my_cert.pub"
299-
```
296+
```powershell
297+
Connect-AzSftp -StorageAccount "<<account_name>>" -CertificateFile "/my_cert.pub"
298+
```
300299

301300
Additionally, you can get the OpenSSH certificate and connect to SFTP by using a single command as follows:
302301

303-
```powershell
304-
Connect-AzAccount
305-
Connect-AzSftp -StorageAccount "<<account_name>>"
306-
```
302+
```powershell
303+
Connect-AzAccount
304+
Connect-AzSftp -StorageAccount "<<account_name>>"
305+
```
307306

308307
For more information about the commands, see [here](/powershell/module/az.sftp/connect-azsftp).
309308

310-
311-
312309
##### [.NET](#tab/dotnet)
313310

314311
Not applicable.

0 commit comments

Comments
 (0)