Skip to content

Commit ce93512

Browse files
jovieirJoão VieiraCopilotYanaXu
authored
[Az.Aks] Enforce RSA as the GenerateSSHKeys default key type (#28998)
Co-authored-by: João Vieira <jovieir@microsoft.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Yan Xu <yanxu1@microsoft.com>
1 parent 8b259ee commit ce93512

File tree

2 files changed

+67
-1
lines changed

2 files changed

+67
-1
lines changed

src/Aks/Aks/ChangeLog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
- Additional information about change #1
1919
-->
2020
## Upcoming Release
21+
* Fixed the default SSH key generation logic in `New-AzAksCluster` to enforce RSA key type (instead of ed25519 that became the default in OpenSSH 9.4 and above)
2122

2223
## Version 7.1.0
2324
* Bumped API version to 2025-08-01

src/Aks/Aks/Commands/NewAzureRmAks.cs

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
using Microsoft.Rest;
3131
using Microsoft.WindowsAzure.Commands.Common;
3232
using Microsoft.WindowsAzure.Commands.Utilities.Common;
33+
using System.Runtime.InteropServices;
3334

3435
namespace Microsoft.Azure.Commands.Aks
3536
{
@@ -311,6 +312,61 @@ private void PreValidate()
311312
}
312313
}
313314

315+
// From OpenSSH 9.4 onwards, the default key type is ed25519, which is not supported in AKS.
316+
// To ensure backward compatibility, we need to check the OpenSSH version installed and adjust the parameters accordingly.
317+
static Version GetOpenSSHVersion()
318+
{
319+
using (Process process = new Process())
320+
{
321+
try
322+
{
323+
// Using runtime information to determine the path to ssh.exe based on OS type.
324+
bool isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
325+
string defaultWindowsSshPath = @"C:\Windows\System32\OpenSSH\ssh.exe";
326+
process.StartInfo.FileName = isWindows && File.Exists(defaultWindowsSshPath) ? defaultWindowsSshPath : "ssh";
327+
process.StartInfo.Arguments = "-V";
328+
process.StartInfo.UseShellExecute = false;
329+
process.StartInfo.RedirectStandardInput = true;
330+
process.StartInfo.RedirectStandardError = true;
331+
process.StartInfo.RedirectStandardOutput = true;
332+
process.StartInfo.CreateNoWindow = true;
333+
process.Start();
334+
335+
string standardOutput = process.StandardOutput.ReadToEnd() + process.StandardError.ReadToEnd();
336+
337+
process.WaitForExit();
338+
// OpenSSH version output follows formats like:
339+
// Windows: "OpenSSH_for_Windows_8.6p1, LibreSSL 3.4.3"
340+
// Windows: "OpenSSH_for_Windows_9.5p1, LibreSSL 3.8.2"
341+
// Linux/macOS: "OpenSSH_9.5p1, OpenSSL 3.0.13 30 Jan 2024"
342+
// We match the common "OpenSSH_" prefix and make "for_Windows_" optional so this works across platforms.
343+
var regMatch = System.Text.RegularExpressions.Regex.Match(standardOutput, @"OpenSSH_(?:for_Windows_)?(\d+)\.(\d+)");
344+
345+
// We don't really care about the patch version, so only return major and minor version.
346+
return regMatch.Success ? new Version(int.Parse(regMatch.Groups[1].Value), int.Parse(regMatch.Groups[2].Value)) : null;
347+
}
348+
// We're not expecting ssh to be missing, but just in case, we catch any exception and return null.
349+
catch
350+
{
351+
return null;
352+
}
353+
finally //Ensure process is properly disposed of and exited
354+
{
355+
if (!process.HasExited)
356+
{
357+
try
358+
{
359+
process.Kill();
360+
}
361+
catch
362+
{
363+
// Ignore exceptions from Kill if process already exited
364+
}
365+
}
366+
}
367+
}
368+
}
369+
314370
private string GenerateSshKeyValue()
315371
{
316372
String generateSshKeyFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".ssh");
@@ -329,8 +385,17 @@ private string GenerateSshKeyValue()
329385
{
330386
try
331387
{
388+
// Validate if OpenSSH version is 9.4 or above to add -t rsa argument
389+
// Which has been defaulted to ed25519 from OpenSSH 9.4 onwards
390+
// https://github.com/openssh/openssh-portable/blob/master/ssh-keygen.c#L70
391+
var openSshVersion = GetOpenSSHVersion();
392+
// If we cannot determine the OpenSSH version, we assume it's below 9.4 to maintain compatibility.
393+
// If openSshVersion isn't null and is >= 9.4, we add the -t rsa argument, otherwise we skip it
394+
var keyTypeArgument = openSshVersion != null && openSshVersion >= new Version(9, 4) ? "-t rsa " : "";
332395
process.StartInfo.FileName = "ssh-keygen";
333-
process.StartInfo.Arguments = String.Format("-f \"{0}\"", generateSshKeyPath);
396+
// if keyTypeArgument is empty, we skip it to maintain compatibility with older OpenSSH versions
397+
// Otherwise, we explicitly set the key type to rsa
398+
process.StartInfo.Arguments = String.Format("{0}-f \"{1}\"", keyTypeArgument, generateSshKeyPath);
334399
process.StartInfo.UseShellExecute = false;
335400
process.StartInfo.RedirectStandardInput = true;
336401
process.StartInfo.RedirectStandardError = true;

0 commit comments

Comments
 (0)