Skip to content

Enabled setting ssh auth scope in environment #27878

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions src/Accounts/Accounts/ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
-->

## Upcoming Release
* Enabled setting the authentication scope for SSH cmdlets by `Set-AzEnvironment -SshAuthScope <String>`.

## Version 5.0.2
* Upgrade Azure.Core to 1.45.0
Expand Down
6 changes: 6 additions & 0 deletions src/Accounts/Accounts/Environment/AddAzureRMEnvironment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,10 @@ public string DataLakeAudience
HelpMessage = "Microsoft Graph Url")]
public string MicrosoftGraphUrl { get; set; }

[Parameter(ParameterSetName = EnvironmentPropertiesParameterSet, Mandatory = false, ValueFromPipelineByPropertyName = true,
HelpMessage = "The scope for authentication when SSH to an Azure VM.")]
public string SshAuthScope { get; set; }

protected override bool RequireDefaultContext()
{
return false;
Expand Down Expand Up @@ -391,6 +395,8 @@ public override void ExecuteCmdlet()
nameof(MicrosoftGraphEndpointResourceId));
SetEndpointIfBound(newEnvironment, AzureEnvironment.ExtendedEndpoint.MicrosoftGraphUrl,
nameof(MicrosoftGraphUrl));
SetEndpointIfBound(newEnvironment, AzureEnvironment.ExtendedEndpoint.AzureSshAuthScope,
nameof(SshAuthScope));
WriteObject(new PSAzureEnvironment(profileClient.AddOrSetEnvironment(newEnvironment)));
}
});
Expand Down
6 changes: 6 additions & 0 deletions src/Accounts/Accounts/Environment/SetAzureRMEnvironment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,10 @@ public string DataLakeAudience
HelpMessage = "Microsoft Graph Url")]
public string MicrosoftGraphUrl { get; set; }

[Parameter(ParameterSetName = EnvironmentPropertiesParameterSet, Mandatory = false, ValueFromPipelineByPropertyName = true,
HelpMessage = "The scope for authentication when SSH to an Azure VM.")]
public string SshAuthScope { get; set; }

protected override bool RequireDefaultContext()
{
return false;
Expand Down Expand Up @@ -364,6 +368,8 @@ public override void ExecuteCmdlet()
nameof(MicrosoftGraphEndpointResourceId));
SetEndpointIfBound(newEnvironment, AzureEnvironment.ExtendedEndpoint.MicrosoftGraphUrl,
nameof(MicrosoftGraphUrl));
SetEndpointIfBound(newEnvironment, AzureEnvironment.ExtendedEndpoint.AzureSshAuthScope,
nameof(SshAuthScope));
WriteObject(new PSAzureEnvironment(profileClient.AddOrSetEnvironment(newEnvironment)));
}
});
Expand Down
22 changes: 19 additions & 3 deletions src/Accounts/Accounts/help/Add-AzEnvironment.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ Add-AzEnvironment [-Name] <String> [[-PublishSettingsFileUrl] <String>] [[-Servi
[-AzureAnalysisServicesEndpointResourceId <String>] [-AzureAttestationServiceEndpointSuffix <String>]
[-AzureAttestationServiceEndpointResourceId <String>] [-AzureSynapseAnalyticsEndpointSuffix <String>]
[-ContainerRegistryEndpointSuffix <String>] [-AzureSynapseAnalyticsEndpointResourceId <String>]
[-MicrosoftGraphEndpointResourceId <String>] [-MicrosoftGraphUrl <String>] [-Scope <ContextModificationScope>]
[-DefaultProfile <IAzureContextContainer>] [-WhatIf] [-Confirm] [<CommonParameters>]
[-MicrosoftGraphEndpointResourceId <String>] [-MicrosoftGraphUrl <String>] [-SshAuthScope <String>]
[-Scope <ContextModificationScope>] [-DefaultProfile <IAzureContextContainer>]
[-WhatIf] [-Confirm] [<CommonParameters>]
```

### ARMEndpoint
Expand Down Expand Up @@ -110,7 +111,7 @@ ExtendedProperties : {}
BatchEndpointResourceId :
```

In this example we are creating a new Azure environment with sample endpoints using Add-AzEnvironment, and then we are changing the value of the ActiveDirectoryEndpoint and GraphEndpoint attributes of the created environment using the cmdlet Set-AzEnvironment.
In this example we are creating a new Azure environment with sample endpoints using Add-AzEnvironment, and then we are changing the value of the ActiveDirectoryEndpoint and GraphEndpoint attributes of the created environment using the cmdlet Set-AzEnvironment.

### Example 2: Discovering a new environment via Uri
```powershell
Expand Down Expand Up @@ -677,6 +678,21 @@ Accept pipeline input: True (ByPropertyName)
Accept wildcard characters: False
```

### -SshAuthScope
The scope for authentication when SSH to an Azure VM.

```yaml
Type: System.String
Parameter Sets: Name
Aliases:

Required: False
Position: Named
Default value: None
Accept pipeline input: True (ByPropertyName)
Accept wildcard characters: False
```

### -StorageEndpoint
Specifies the endpoint for storage (blob, table, queue, and file) access.

Expand Down
3 changes: 3 additions & 0 deletions src/Accounts/Accounts/help/Az.Accounts.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ Exports all the configs into a file so that it can be imported on another machin
### [Get-AzAccessToken](Get-AzAccessToken.md)
Get secure access token. When using -ResourceUrl, please make sure the value does match current Azure environment. You may refer to the value of `(Get-AzContext).Environment`.

> [!NOTE]
> For security purposes, the default output type has been changed from a plain text `String` to `SecureString`. For more information, see [Protect secrets in Azure PowerShell](https://go.microsoft.com/fwlink/?linkid=2258844).

### [Get-AzConfig](Get-AzConfig.md)
Gets the configs of Azure PowerShell.

Expand Down
22 changes: 19 additions & 3 deletions src/Accounts/Accounts/help/Set-AzEnvironment.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ Set-AzEnvironment [-Name] <String> [[-PublishSettingsFileUrl] <String>] [[-Servi
[-AzureAnalysisServicesEndpointResourceId <String>] [-AzureAttestationServiceEndpointSuffix <String>]
[-AzureAttestationServiceEndpointResourceId <String>] [-AzureSynapseAnalyticsEndpointSuffix <String>]
[-ContainerRegistryEndpointSuffix <String>] [-AzureSynapseAnalyticsEndpointResourceId <String>]
[-MicrosoftGraphEndpointResourceId <String>] [-MicrosoftGraphUrl <String>] [-Scope <ContextModificationScope>]
[-DefaultProfile <IAzureContextContainer>] [-WhatIf] [-Confirm] [<CommonParameters>]
[-MicrosoftGraphEndpointResourceId <String>] [-MicrosoftGraphUrl <String>] [-SshAuthScope <String>]
[-Scope <ContextModificationScope>] [-DefaultProfile <IAzureContextContainer>]
[-WhatIf] [-Confirm] [<CommonParameters>]
```

### ARMEndpoint
Expand Down Expand Up @@ -76,7 +77,7 @@ ActiveDirectoryServiceEndpointResourceId : TestADApplicationId
AdTenant :
GalleryUrl : TestGalleryEndpoint
ManagementPortalUrl :
ServiceManagementUrl :
ServiceManagementUrl :
PublishSettingsFileUrl :
ResourceManagerUrl : TestRMEndpoint
SqlDatabaseDnsSuffix :
Expand Down Expand Up @@ -599,6 +600,21 @@ Accept pipeline input: True (ByPropertyName)
Accept wildcard characters: False
```

### -SshAuthScope
The scope for authentication when SSH to an Azure VM.

```yaml
Type: System.String
Parameter Sets: Name
Aliases:

Required: False
Position: Named
Default value: None
Accept pipeline input: True (ByPropertyName)
Accept wildcard characters: False
```

### -StorageEndpoint
Specifies the endpoint for storage (blob, table, queue, and file) access.

Expand Down
25 changes: 14 additions & 11 deletions src/Accounts/Authentication/Factories/SshCredentialFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
using Microsoft.Azure.Commands.Common.Authentication.Abstractions;
using Microsoft.Azure.Commands.Common.Authentication.Abstractions.Models;
using Microsoft.Azure.Commands.Common.Authentication.Properties;
using Microsoft.Azure.Commands.Common.Exceptions;
using Microsoft.Identity.Client.SSHCertificates;
using Microsoft.WindowsAzure.Commands.Utilities.Common;

Expand All @@ -29,12 +30,12 @@ namespace Microsoft.Azure.Commands.Common.Authentication.Factories
{
public class SshCredentialFactory : ISshCredentialFactory
{

private readonly Dictionary<string, string> CloudToScope = new Dictionary<string, string>()
// kept for backward-compatibility
private readonly Dictionary<string, string> CloudToScope = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase)
{
{ "azurecloud", "https://pas.windows.net/CheckMyAccess/Linux/.default" },
{ "azurechinacloud", "https://pas.chinacloudapi.cn/CheckMyAccess/Linux/.default" },
{ "azureusgovernment", "https://pasff.usgovcloudapi.net/CheckMyAccess/Linux/.default" },
{ EnvironmentName.AzureCloud, AzureEnvironmentConstants.AzureSshAuthScope },
{ EnvironmentName.AzureChinaCloud, AzureEnvironmentConstants.ChinaSshAuthScope },
{ EnvironmentName.AzureUSGovernment, AzureEnvironmentConstants.USGovernmentSshAuthScope },
};

private string CreateJwk(RSAParameters rsaKeyInfo, out string keyId)
Expand Down Expand Up @@ -69,12 +70,8 @@ public SshCredential GetSshCredential(IAzureContext context, RSAParameters rsaKe
}

var publicClient = tokenCacheProvider.CreatePublicClient(context.Environment.ActiveDirectoryAuthority, context.Tenant.Id);
string cloudName = context.Environment.Name.ToLower();
string scope = CloudToScope.GetValueOrDefault(cloudName, null);
if (scope == null)
{
throw new Exception(string.Format("Unsupported cloud {0}. Supported clouds include AzureCloud,AzureChinaCloud,AzureUSGovernment.", cloudName));
}
string scope = GetAuthScope(context.Environment)
?? throw new AzPSKeyNotFoundException(string.Format(Resources.ErrorSshAuthScopeNotSet, context.Environment.Name));
List<string> scopes = new List<string>() { scope };
var jwk = CreateJwk(rsaKeyInfo, out string keyId);

Expand All @@ -92,5 +89,11 @@ public SshCredential GetSshCredential(IAzureContext context, RSAParameters rsaKe
};
return resultToken;
}

private string GetAuthScope(IAzureEnvironment environment)
{
return environment.GetProperty(AzureEnvironment.ExtendedEndpoint.AzureSshAuthScope)
?? CloudToScope.GetValueOrDefault(environment.Name.ToLower(), null);
Copy link
Preview

Copilot AI Jun 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the CloudToScope dictionary now uses StringComparer.InvariantCultureIgnoreCase, converting environment.Name to lower case is unnecessary and could be removed for clarity.

Suggested change
?? CloudToScope.GetValueOrDefault(environment.Name.ToLower(), null);
?? CloudToScope.GetValueOrDefault(environment.Name, null);

Copilot uses AI. Check for mistakes.

}
}
}
9 changes: 9 additions & 0 deletions src/Accounts/Authentication/Properties/Resources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions src/Accounts/Authentication/Properties/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -422,4 +422,8 @@
<data name="AuthenticationTelemetryRecordPushError" xml:space="preserve">
<value>Fail to push authentication telemetry record, please check the CmdletcContext with Id {0}.</value>
</data>
<data name="ErrorSshAuthScopeNotSet" xml:space="preserve">
<value>The scope of authenticating for SSH is not set. Please run "Set-AzEnvironment -Name {0} -SshAuthScope ..." to set it first.</value>
<comment>0 = environment name</comment>
</data>
</root>
34 changes: 17 additions & 17 deletions tools/Common.Netcore.Dependencies.targets
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,22 @@
<ItemGroup>
<PackageReference Include="Microsoft.Rest.ClientRuntime" Version="2.3.24"/>
<PackageReference Include="Microsoft.Rest.ClientRuntime.Azure" Version="3.3.19"/>
<PackageReference Include="Microsoft.Azure.PowerShell.Clients.Aks" Version="1.3.108-preview"/>
<PackageReference Include="Microsoft.Azure.PowerShell.Authentication.Abstractions" Version="1.3.108-preview"/>
<PackageReference Include="Microsoft.Azure.PowerShell.Clients.Authorization" Version="1.3.108-preview"/>
<PackageReference Include="Microsoft.Azure.PowerShell.Common" Version="1.3.108-preview"/>
<PackageReference Include="Microsoft.Azure.PowerShell.Clients.Compute" Version="1.3.108-preview"/>
<PackageReference Include="Microsoft.Azure.PowerShell.Clients.Graph.Rbac" Version="1.3.108-preview"/>
<PackageReference Include="Microsoft.Azure.PowerShell.Clients.KeyVault" Version="1.3.108-preview"/>
<PackageReference Include="Microsoft.Azure.PowerShell.Clients.Monitor" Version="1.3.108-preview"/>
<PackageReference Include="Microsoft.Azure.PowerShell.Clients.Network" Version="1.3.108-preview"/>
<PackageReference Include="Microsoft.Azure.PowerShell.Clients.PolicyInsights" Version="1.3.108-preview"/>
<PackageReference Include="Microsoft.Azure.PowerShell.Clients.ResourceManager" Version="1.3.108-preview"/>
<PackageReference Include="Microsoft.Azure.PowerShell.Storage" Version="1.3.108-preview"/>
<PackageReference Include="Microsoft.Azure.PowerShell.Clients.Storage.Management" Version="1.3.108-preview"/>
<PackageReference Include="Microsoft.Azure.PowerShell.Strategies" Version="1.3.108-preview"/>
<PackageReference Include="Microsoft.Azure.PowerShell.Clients.Websites" Version="1.3.108-preview"/>
<PackageReference Include="Microsoft.Azure.PowerShell.Common.Share" Version="1.3.108-preview"/>
<PackageReference Include="Microsoft.Azure.PowerShell.Clients.Aks" Version="1.3.109-preview"/>
<PackageReference Include="Microsoft.Azure.PowerShell.Authentication.Abstractions" Version="1.3.109-preview"/>
<PackageReference Include="Microsoft.Azure.PowerShell.Clients.Authorization" Version="1.3.109-preview"/>
<PackageReference Include="Microsoft.Azure.PowerShell.Common" Version="1.3.109-preview"/>
<PackageReference Include="Microsoft.Azure.PowerShell.Clients.Compute" Version="1.3.109-preview"/>
<PackageReference Include="Microsoft.Azure.PowerShell.Clients.Graph.Rbac" Version="1.3.109-preview"/>
<PackageReference Include="Microsoft.Azure.PowerShell.Clients.KeyVault" Version="1.3.109-preview"/>
<PackageReference Include="Microsoft.Azure.PowerShell.Clients.Monitor" Version="1.3.109-preview"/>
<PackageReference Include="Microsoft.Azure.PowerShell.Clients.Network" Version="1.3.109-preview"/>
<PackageReference Include="Microsoft.Azure.PowerShell.Clients.PolicyInsights" Version="1.3.109-preview"/>
<PackageReference Include="Microsoft.Azure.PowerShell.Clients.ResourceManager" Version="1.3.109-preview"/>
<PackageReference Include="Microsoft.Azure.PowerShell.Storage" Version="1.3.109-preview"/>
<PackageReference Include="Microsoft.Azure.PowerShell.Clients.Storage.Management" Version="1.3.109-preview"/>
<PackageReference Include="Microsoft.Azure.PowerShell.Strategies" Version="1.3.109-preview"/>
<PackageReference Include="Microsoft.Azure.PowerShell.Clients.Websites" Version="1.3.109-preview"/>
<PackageReference Include="Microsoft.Azure.PowerShell.Common.Share" Version="1.3.109-preview"/>
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
</ItemGroup>
<ItemGroup>
Expand All @@ -37,7 +37,7 @@
<PackageReference Include="PowerShellStandard.Library" Version="5.1.0" PrivateAssets="All" />
</ItemGroup>
<PropertyGroup>
<StorageToolsPath>$(NugetPackageRoot)\microsoft.azure.powershell.storage\1.3.108-preview\tools\</StorageToolsPath>
<StorageToolsPath>$(NugetPackageRoot)\microsoft.azure.powershell.storage\1.3.109-preview\tools\</StorageToolsPath>
</PropertyGroup>
<ItemGroup Condition="'$(OmitJsonPackage)' != 'true'">
<PackageReference Include="Newtonsoft.Json" Version="13.0.2"/>
Expand Down
Loading