diff --git a/src/Aks/Aks.Test/ScenarioTests/KubernetesTests.cs b/src/Aks/Aks.Test/ScenarioTests/KubernetesTests.cs index f0bb10e63958..1b4fbef4ece0 100644 --- a/src/Aks/Aks.Test/ScenarioTests/KubernetesTests.cs +++ b/src/Aks/Aks.Test/ScenarioTests/KubernetesTests.cs @@ -45,6 +45,13 @@ public void TestAzureKubernetesAddons() TestController.NewInstance.RunPowerShellTest(_logger, "Test-NewAzAksAddons"); } + [Fact(Skip = "Please make sure you have graph directory.read permission which is required for grant acrpull permission.")] + [Trait(Category.AcceptanceType, Category.CheckIn)] + public void TestNewAzAksWithAcr() + { + TestController.NewInstance.RunPowerShellTest(_logger, "Test-NewAzAksWithAcr"); + } + [Fact(Skip = "Updating service principal profile is not allowed on MSI cluster.")] [Trait(Category.AcceptanceType, Category.CheckIn)] public void TestResetAzureKubernetesServicePrincipal() diff --git a/src/Aks/Aks.Test/ScenarioTests/KubernetesTests.ps1 b/src/Aks/Aks.Test/ScenarioTests/KubernetesTests.ps1 index b48d69d576d7..ad41a2b9de47 100644 --- a/src/Aks/Aks.Test/ScenarioTests/KubernetesTests.ps1 +++ b/src/Aks/Aks.Test/ScenarioTests/KubernetesTests.ps1 @@ -39,7 +39,7 @@ function Test-NewAzAksWithAcr $kubeClusterName = Get-RandomClusterName $acrName = Get-RandomRegistryName $location = Get-ProviderLocation "Microsoft.ContainerService/managedClusters" - $nodeVmSize = "Standard_A2" + $nodeVmSize = "Standard_D2_v2" try { @@ -59,6 +59,14 @@ function Test-NewAzAksWithAcr Assert-AreEqual 2 $cluster.AgentPoolProfiles[0].Count; $cluster | Import-AzAksCredential -Force $cluster | Remove-AzAksCluster -Force + $roleAssignment = Get-AzRoleAssignment -ResourceGroupName $resourceGroupName | Where-Object { ($_.RoleDefinitionName -eq 'AcrPull') -and ($_.DisplayName -eq $acrName) } + Assert-NotNull $roleAssignment + Set-AzAksCluster -ResourceGroupName $resourceGroupName -Name $kubeClusterName -AcrNameToDetach $acrName + $roleAssignment = Get-AzRoleAssignment -ResourceGroupName $resourceGroupName | Where-Object { ($_.RoleDefinitionName -eq 'AcrPull') -and ($_.DisplayName -eq $acrName) } + Assert-Null $roleAssignment + Set-AzAksCluster -ResourceGroupName $resourceGroupName -Name $kubeClusterName -AcrNameToAttach $acrName + $roleAssignment = Get-AzRoleAssignment -ResourceGroupName $resourceGroupName | Where-Object { ($_.RoleDefinitionName -eq 'AcrPull') -and ($_.DisplayName -eq $acrName) } + Assert-NotNull $roleAssignment } finally { diff --git a/src/Aks/Aks.Test/ScenarioTests/TestController.cs b/src/Aks/Aks.Test/ScenarioTests/TestController.cs index 1b21fe044067..372d2c377ded 100644 --- a/src/Aks/Aks.Test/ScenarioTests/TestController.cs +++ b/src/Aks/Aks.Test/ScenarioTests/TestController.cs @@ -14,6 +14,8 @@ using Microsoft.Azure.ServiceManagement.Common.Models; using Microsoft.Azure.Management.ContainerService; using Microsoft.Azure.Management.Authorization.Version2015_07_01; +using Microsoft.Azure.Graph.RBAC.Version1_6; +using Microsoft.Azure.Commands.Common.Authentication.Abstractions; namespace Commands.Aks.Test.ScenarioTests { @@ -30,6 +32,9 @@ public TestController() public static TestController NewInstance => new TestController(); + public string UserDomain { get; private set; } + public GraphRbacManagementClient InternalGraphRbacManagementClient { get; private set; } + public ResourceManagementClient InternalResourceManagementClient { get; private set; } public AuthorizationManagementClient InternalAuthorizationManagementClient { get; private set; } @@ -44,6 +49,7 @@ public void RunPowerShellTest(XunitTracingInterceptor logger, params string[] sc var d = new Dictionary { + {"Microsoft.Resources", null}, {"Microsoft.Features", null}, {"Microsoft.Authorization", null} }; @@ -108,13 +114,26 @@ private void SetupManagementClients(MockContext context) { ContainerServiceClient = GetContainerServiceClient(context); InternalResourceManagementClient = GetInternalResourceManagementClient(context); - _helper.SetupManagementClients(ContainerServiceClient, InternalResourceManagementClient); + InternalAuthorizationManagementClient = GetAuthorizationManagementClient(context); + InternalGraphRbacManagementClient = GetGraphRbacManagementClient(context); + _helper.SetupManagementClients(ContainerServiceClient, + InternalResourceManagementClient, + InternalAuthorizationManagementClient, + InternalGraphRbacManagementClient); } private static ContainerServiceClient GetContainerServiceClient(MockContext context) { return context.GetServiceClient(); } + private GraphRbacManagementClient GetGraphRbacManagementClient(MockContext context) + { + return context.GetServiceClient(); + } + private static AuthorizationManagementClient GetAuthorizationManagementClient(MockContext context) + { + return context.GetServiceClient(); + } private static ResourceManagementClient GetInternalResourceManagementClient(MockContext context) { return context.GetServiceClient(); diff --git a/src/Aks/Aks/ChangeLog.md b/src/Aks/Aks/ChangeLog.md index b64e1d6ab1c3..0f4b9643f1cf 100644 --- a/src/Aks/Aks/ChangeLog.md +++ b/src/Aks/Aks/ChangeLog.md @@ -18,7 +18,9 @@ - Additional information about change #1 --> ## Upcoming Release -* Add `Set-AzAksClusterCredential` to reset the ServicePrincipal of an existing AKS cluster. +* Added support `AcrNameToAttach` in `Set-AzAksCluster`. [#14692] +* Added support `AcrNameToDetach` in `Set-AzAksCluster`. [#14693] +* Added `Set-AzAksClusterCredential` to reset the ServicePrincipal of an existing AKS cluster. ## Version 2.0.2 * Refined error messages of cmdlet failure. diff --git a/src/Aks/Aks/Commands/CreateOrUpdateKubeBase.cs b/src/Aks/Aks/Commands/CreateOrUpdateKubeBase.cs index b231439a6593..ef45255a1a15 100644 --- a/src/Aks/Aks/Commands/CreateOrUpdateKubeBase.cs +++ b/src/Aks/Aks/Commands/CreateOrUpdateKubeBase.cs @@ -116,61 +116,15 @@ public abstract class CreateOrUpdateKubeBase : KubeCmdletBase [Alias("SshKeyPath")] public string SshKeyValue { get; set; } + [Parameter(Mandatory = false, HelpMessage = "Grant the 'acrpull' role of the specified ACR to AKS Service Principal, e.g. myacr")] + public string AcrNameToAttach { get; set; } + [Parameter(Mandatory = false, HelpMessage = "Run cmdlet in the background")] public SwitchParameter AsJob { get; set; } [Parameter(Mandatory = false)] public Hashtable Tag { get; set; } - protected virtual ManagedCluster BuildNewCluster() - { - BeforeBuildNewCluster(); - - var defaultAgentPoolProfile = new ManagedClusterAgentPoolProfile( - name: NodeName ?? "default", - count: NodeCount, - vmSize: NodeVmSize, - osDiskSizeGB: NodeOsDiskSize); - - if (this.IsParameterBound(c => c.NodeMinCount)) - { - defaultAgentPoolProfile.MinCount = NodeMinCount; - } - if (this.IsParameterBound(c => c.NodeMaxCount)) - { - defaultAgentPoolProfile.MaxCount = NodeMaxCount; - } - if (EnableNodeAutoScaling.IsPresent) - { - defaultAgentPoolProfile.EnableAutoScaling = EnableNodeAutoScaling.ToBool(); - } - - var pubKey = - new List { new ContainerServiceSshPublicKey(SshKeyValue) }; - - var linuxProfile = - new ContainerServiceLinuxProfile(LinuxProfileAdminUserName, - new ContainerServiceSshConfiguration(pubKey)); - - var acsServicePrincipal = EnsureServicePrincipal(ServicePrincipalIdAndSecret?.UserName, ServicePrincipalIdAndSecret?.Password?.ConvertToString()); - - var spProfile = new ManagedClusterServicePrincipalProfile( - acsServicePrincipal.SpId, - acsServicePrincipal.ClientSecret); - - WriteVerbose(string.Format(Resources.DeployingYourManagedKubeCluster, AcsSpFilePath)); - var managedCluster = new ManagedCluster( - Location, - name: Name, - tags: TagsConversionHelper.CreateTagDictionary(Tag, true), - dnsPrefix: DnsNamePrefix, - kubernetesVersion: KubernetesVersion, - agentPoolProfiles: new List { defaultAgentPoolProfile }, - linuxProfile: linuxProfile, - servicePrincipalProfile: spProfile); - return managedCluster; - } - protected void BeforeBuildNewCluster() { if (!string.IsNullOrEmpty(ResourceGroupName) && string.IsNullOrEmpty(Location)) @@ -271,17 +225,15 @@ protected AcsServicePrincipal EnsureServicePrincipal(string spId = null, string { clientSecret = RandomBase64String(16); } - var salt = RandomBase64String(3); - var url = $"http://{salt}.{DnsNamePrefix}.{Location}.cloudapp.azure.com"; - acsServicePrincipal = BuildServicePrincipal(Name, url, clientSecret); + acsServicePrincipal = BuildServicePrincipal(Name, clientSecret); WriteVerbose(Resources.CreatedANewServicePrincipalAndAssignedTheContributorRole); StoreServicePrincipal(acsServicePrincipal); } return acsServicePrincipal; } - private AcsServicePrincipal BuildServicePrincipal(string name, string url, string clientSecret) + private AcsServicePrincipal BuildServicePrincipal(string name, string clientSecret) { var pwCreds = new PasswordCredential( value: clientSecret, @@ -291,8 +243,8 @@ private AcsServicePrincipal BuildServicePrincipal(string name, string url, strin var app = GraphClient.Applications.Create(new ApplicationCreateParameters( false, name, - new List { url }, - url, + new List { }, + null, passwordCredentials: new List { pwCreds })); ServicePrincipal sp = null; @@ -316,6 +268,22 @@ private AcsServicePrincipal BuildServicePrincipal(string name, string url, strin return new AcsServicePrincipal { SpId = app.AppId, ClientSecret = clientSecret, ObjectId = app.ObjectId }; } + protected RoleAssignment GetRoleAssignmentWithRoleDefinitionId(string roleDefinitionId) + { + RoleAssignment roleAssignment = null; + var actionSuccess = RetryAction(() => + { + roleAssignment = AuthClient.RoleAssignments.List().Where(x => x.Properties.RoleDefinitionId == roleDefinitionId && x.Name == Name).FirstOrDefault(); + }); + if (!actionSuccess) + { + throw new AzPSInvalidOperationException( + Resources.CouldNotGetAcrRoleAssignment, + desensitizedMessage: Resources.CouldNotGetAcrRoleAssignment); + } + return roleAssignment; + } + protected void AddAcrRoleAssignment(string acrName, string acrParameterName, AcsServicePrincipal acsServicePrincipal) { string acrResourceId = null; @@ -335,8 +303,14 @@ protected void AddAcrRoleAssignment(string acrName, string acrParameterName, Acs } var roleId = GetRoleId("acrpull", acrResourceId); + RoleAssignment roleAssignment = GetRoleAssignmentWithRoleDefinitionId(roleId); + if (roleAssignment != null) + { + WriteWarning(string.Format(Resources.AcrRoleAssignmentIsAlreadyExist, acrResourceId)); + return; + } var spObjectId = acsServicePrincipal.ObjectId; - if(spObjectId == null) + if (spObjectId == null) { try { diff --git a/src/Aks/Aks/Commands/NewAzureRmAks.cs b/src/Aks/Aks/Commands/NewAzureRmAks.cs index 5b9f8587374a..a5a2877993d8 100644 --- a/src/Aks/Aks/Commands/NewAzureRmAks.cs +++ b/src/Aks/Aks/Commands/NewAzureRmAks.cs @@ -19,13 +19,19 @@ using System.IO; using System.Linq; using System.Management.Automation; +using System.Security; using Microsoft.Azure.Commands.Aks.Models; using Microsoft.Azure.Commands.Aks.Properties; +using Microsoft.Azure.Commands.Aks.Utils; using Microsoft.Azure.Commands.Common; using Microsoft.Azure.Commands.Common.Exceptions; +using Microsoft.Azure.Commands.ResourceManager.Common.ArgumentCompleters; +using Microsoft.Azure.Commands.ResourceManager.Common.Tags; using Microsoft.Azure.Management.ContainerService; +using Microsoft.Azure.Management.ContainerService.Models; using Microsoft.Rest; +using Microsoft.WindowsAzure.Commands.Common; using Microsoft.WindowsAzure.Commands.Common.CustomAttributes; using Microsoft.WindowsAzure.Commands.Utilities.Common; @@ -35,8 +41,66 @@ namespace Microsoft.Azure.Commands.Aks [Cmdlet("New", ResourceManager.Common.AzureRMConstants.AzureRMPrefix + "AksCluster", DefaultParameterSetName = DefaultParamSet, SupportsShouldProcess = true)] [Alias("New-" + ResourceManager.Common.AzureRMConstants.AzureRMPrefix + "Aks")] [OutputType(typeof(PSKubernetesCluster))] - public class NewAzureRmAks : NewKubeBase + public class NewAzureRmAks : CreateOrUpdateKubeBase { + [Parameter(Mandatory = false, HelpMessage = "Represents types of an node pool. Possible values include: 'VirtualMachineScaleSets', 'AvailabilitySet'")] + [PSArgumentCompleter("AvailabilitySet", "VirtualMachineScaleSets")] + public string NodeVmSetType { get; set; } + + [Parameter(Mandatory = false, HelpMessage = "VNet SubnetID specifies the VNet's subnet identifier.")] + public string NodeVnetSubnetID { get; set; } + + [Parameter(Mandatory = false, HelpMessage = "Maximum number of pods that can run on node.")] + public int NodeMaxPodCount { get; set; } + + [Parameter(Mandatory = false, HelpMessage = "ScaleSetPriority to be used to specify virtual machine scale set priority. Default to regular.")] + [PSArgumentCompleter("Low", "Regular")] + public string NodeSetPriority { get; set; } + + [Parameter(Mandatory = false, HelpMessage = "NodePoolMode represents mode of an node pool.")] + [PSArgumentCompleter("System", "User")] + public string NodePoolMode { get; set; } = "System"; + + [Parameter(Mandatory = false, HelpMessage = "ScaleSetEvictionPolicy to be used to specify eviction policy for low priority virtual machine scale set. Default to Delete.")] + [PSArgumentCompleter("Delete", "Deallocate")] + public string NodeScaleSetEvictionPolicy { get; set; } + + [Parameter(Mandatory = false, HelpMessage = "Add-on names to be enabled when cluster is created.")] + [ValidateNotNullOrEmpty()] + [PSArgumentCompleter("HttpApplicationRouting", "Monitoring", "VirtualNode", "AzurePolicy", "KubeDashboard")] + public string[] AddOnNameToBeEnabled { get; set; } + + [Parameter(Mandatory = false, + ValueFromPipelineByPropertyName = true, + HelpMessage = "Resource Id of the workspace of Monitoring addon.")] + [ValidateNotNullOrEmpty] + public string WorkspaceResourceId { get; set; } + + [Parameter(Mandatory = false, + ValueFromPipelineByPropertyName = true, + HelpMessage = "Subnet name of VirtualNode addon.")] + [ValidateNotNullOrEmpty] + public string SubnetName { get; set; } + + [Parameter(Mandatory = false, HelpMessage = "Whether to enable Kubernetes Role-Based Access")] + public SwitchParameter EnableRbac { get; set; } + + [Parameter(Mandatory = false, HelpMessage = "The administrator username to use for Windows VMs.")] + public string WindowsProfileAdminUserName { get; set; } + + [Parameter(Mandatory = false, HelpMessage = "The administrator password to use for Windows VMs. Password requirement:" + + "At least one lower case, one upper case, one special character !@#$%^&*(), the minimum lenth is 12.")] + [ValidateSecureString(RegularExpression = "^(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%\\^&\\*\\(\\)])[a-zA-Z\\d!@#$%\\^&\\*\\(\\)]{12,123}$", ParameterName = nameof(WindowsProfileAdminUserPassword))] + public SecureString WindowsProfileAdminUserPassword { get; set; } + + [Parameter(Mandatory = false, HelpMessage = "Network plugin used for building Kubernetes network.")] + [PSArgumentCompleter("azure", "kubenet")] + public string NetworkPlugin { get; set; } = "azure"; + + [Parameter(Mandatory = false, HelpMessage = "The load balancer sku for the managed cluster.")] + [PSArgumentCompleter("basic", "standard")] + public string LoadBalancerSku { get; set; } + [Parameter(Mandatory = false, HelpMessage = "Create cluster even if it already exists")] public SwitchParameter Force { get; set; } @@ -45,6 +109,8 @@ public class NewAzureRmAks : NewKubeBase HelpMessage = "Generate ssh key file to folder {HOME}/.ssh/ using pre-installed ssh-keygen.")] public SwitchParameter GenerateSshKey { get; set; } + private AcsServicePrincipal acsServicePrincipal; + public override void ExecuteCmdlet() { base.ExecuteCmdlet(); @@ -59,6 +125,11 @@ public override void ExecuteCmdlet() { var cluster = Client.ManagedClusters.CreateOrUpdate(ResourceGroupName, Name, managedCluster); var psObj = PSMapper.Instance.Map(cluster); + + if (this.IsParameterBound(c => c.AcrNameToAttach)) + { + AddAcrRoleAssignment(AcrNameToAttach, nameof(AcrNameToAttach), acsServicePrincipal); + } WriteObject(psObj); } catch (ValidationException e) @@ -190,5 +261,148 @@ protected void PrepareParameter() SshKeyValue = GenerateSshKeyValue(); } } + private ManagedCluster BuildNewCluster() + { + BeforeBuildNewCluster(); + + var pubKey = + new List { new ContainerServiceSshPublicKey(SshKeyValue) }; + + var linuxProfile = + new ContainerServiceLinuxProfile(LinuxProfileAdminUserName, + new ContainerServiceSshConfiguration(pubKey)); + + acsServicePrincipal = EnsureServicePrincipal(ServicePrincipalIdAndSecret?.UserName, ServicePrincipalIdAndSecret?.Password?.ConvertToString()); + + var spProfile = new ManagedClusterServicePrincipalProfile( + acsServicePrincipal.SpId, + acsServicePrincipal.ClientSecret); + + var aadProfile = GetAadProfile(); + + var defaultAgentPoolProfile = GetAgentPoolProfile(); + + var windowsProfile = GetWindowsProfile(); + + var networkProfile = GetNetworkProfile(); + + var addonProfiles = CreateAddonsProfiles(); + + WriteVerbose(string.Format(Resources.DeployingYourManagedKubeCluster, AcsSpFilePath)); + + var managedCluster = new ManagedCluster( + Location, + name: Name, + tags: TagsConversionHelper.CreateTagDictionary(Tag, true), + dnsPrefix: DnsNamePrefix, + kubernetesVersion: KubernetesVersion, + agentPoolProfiles: new List { defaultAgentPoolProfile }, + linuxProfile: linuxProfile, + windowsProfile: windowsProfile, + servicePrincipalProfile: spProfile, + aadProfile: aadProfile, + addonProfiles: addonProfiles, + networkProfile: networkProfile); + + if (EnableRbac.IsPresent) + { + managedCluster.EnableRBAC = EnableRbac; + } + //if(EnablePodSecurityPolicy.IsPresent) + //{ + // managedCluster.EnablePodSecurityPolicy = EnablePodSecurityPolicy; + //} + + return managedCluster; + } + + private ContainerServiceNetworkProfile GetNetworkProfile() + { + var networkProfile = new ContainerServiceNetworkProfile(); + networkProfile.NetworkPlugin = NetworkPlugin; + networkProfile.LoadBalancerSku = LoadBalancerSku; + return networkProfile; + } + + private ManagedClusterWindowsProfile GetWindowsProfile() + { + ManagedClusterWindowsProfile windowsProfile = null; + + if (!string.IsNullOrEmpty(WindowsProfileAdminUserName) || + WindowsProfileAdminUserPassword != null) + { + windowsProfile = new ManagedClusterWindowsProfile(WindowsProfileAdminUserName, + WindowsProfileAdminUserPassword?.ConvertToString()); + } + return windowsProfile; + } + + private ManagedClusterAgentPoolProfile GetAgentPoolProfile() + { + var defaultAgentPoolProfile = new ManagedClusterAgentPoolProfile( + name: NodeName ?? "default", + count: NodeCount, + vmSize: NodeVmSize, + osDiskSizeGB: NodeOsDiskSize, + type: NodeVmSetType ?? "VirtualMachineScaleSets", + vnetSubnetID: NodeVnetSubnetID); + defaultAgentPoolProfile.OsType = "Linux"; + if (this.IsParameterBound(c => c.NodeMaxPodCount)) + { + defaultAgentPoolProfile.MaxPods = NodeMaxPodCount; + } + if (this.IsParameterBound(c => c.NodeMinCount)) + { + defaultAgentPoolProfile.MinCount = NodeMinCount; + } + if (this.IsParameterBound(c => c.NodeMaxCount)) + { + defaultAgentPoolProfile.MaxCount = NodeMaxCount; + } + if (EnableNodeAutoScaling.IsPresent) + { + defaultAgentPoolProfile.EnableAutoScaling = EnableNodeAutoScaling.ToBool(); + } + //if (EnableNodePublicIp.IsPresent) + //{ + // defaultAgentPoolProfile.EnableNodePublicIP = EnableNodePublicIp.ToBool(); + //} + if (this.IsParameterBound(c => c.NodeScaleSetEvictionPolicy)) + { + defaultAgentPoolProfile.ScaleSetEvictionPolicy = NodeScaleSetEvictionPolicy; + } + if (this.IsParameterBound(c => c.NodeSetPriority)) + { + defaultAgentPoolProfile.ScaleSetPriority = NodeSetPriority; + } + defaultAgentPoolProfile.Mode = NodePoolMode; + + return defaultAgentPoolProfile; + } + + private ManagedClusterAADProfile GetAadProfile() + { + ManagedClusterAADProfile aadProfile = null; + //if (!string.IsNullOrEmpty(AadProfileClientAppId) || !string.IsNullOrEmpty(AadProfileServerAppId) || + // !string.IsNullOrEmpty(AadProfileServerAppSecret) || !string.IsNullOrEmpty(AadProfileTenantId)) + //{ + // aadProfile = new ManagedClusterAADProfile(clientAppID: AadProfileClientAppId, serverAppID: AadProfileServerAppId, + // serverAppSecret: AadProfileServerAppSecret, tenantID: AadProfileTenantId); + //} + return aadProfile; + } + + private IDictionary CreateAddonsProfiles() + { + if (this.IsParameterBound(c => c.AddOnNameToBeEnabled)) + { + Dictionary addonProfiles = new Dictionary(); + return AddonUtils.EnableAddonsProfile(addonProfiles, AddOnNameToBeEnabled, nameof(AddOnNameToBeEnabled), WorkspaceResourceId, nameof(WorkspaceResourceId), SubnetName, nameof(SubnetName)); + } + else + { + return null; + } + } } } diff --git a/src/Aks/Aks/Commands/NewKubeBase.cs b/src/Aks/Aks/Commands/NewKubeBase.cs deleted file mode 100644 index 3c5b3ce98b69..000000000000 --- a/src/Aks/Aks/Commands/NewKubeBase.cs +++ /dev/null @@ -1,273 +0,0 @@ -// ---------------------------------------------------------------------------------- -// -// Copyright Microsoft Corporation -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ---------------------------------------------------------------------------------- - - -using System; -using System.Collections.Generic; -using System.IO; -using System.Management.Automation; -using System.Security; -using Microsoft.Azure.Commands.Aks.Properties; -using Microsoft.Azure.Commands.Aks.Utils; -using Microsoft.Azure.Commands.ResourceManager.Common.ArgumentCompleters; -using Microsoft.Azure.Commands.ResourceManager.Common.Tags; -using Microsoft.Azure.Management.ContainerService.Models; -using Microsoft.WindowsAzure.Commands.Common; -using Microsoft.WindowsAzure.Commands.Common.CustomAttributes; -using Microsoft.WindowsAzure.Commands.Utilities.Common; - -namespace Microsoft.Azure.Commands.Aks -{ - public abstract class NewKubeBase : CreateOrUpdateKubeBase - { - [Parameter(Mandatory = false, HelpMessage = "Represents types of an node pool. Possible values include: 'VirtualMachineScaleSets', 'AvailabilitySet'")] - [PSArgumentCompleter("AvailabilitySet", "VirtualMachineScaleSets")] - public string NodeVmSetType { get; set; } - - [Parameter(Mandatory = false, HelpMessage = "VNet SubnetID specifies the VNet's subnet identifier.")] - public string NodeVnetSubnetID { get; set; } - - [Parameter(Mandatory = false, HelpMessage = "Maximum number of pods that can run on node.")] - public int NodeMaxPodCount { get; set; } - - ////Hide it as it expects GA by around May - //[Parameter(Mandatory = false, HelpMessage = "Whether to enable public IP for nodes")] - //public SwitchParameter EnableNodePublicIp { get; set; } - - [Parameter(Mandatory = false, HelpMessage = "ScaleSetPriority to be used to specify virtual machine scale set priority. Default to regular.")] - [PSArgumentCompleter("Low", "Regular")] - public string NodeSetPriority { get; set; } - - [Parameter(Mandatory = false, HelpMessage = "NodePoolMode represents mode of an node pool.")] - [PSArgumentCompleter("System", "User")] - public string NodePoolMode { get; set; } = "System"; - - [Parameter(Mandatory = false, HelpMessage = "ScaleSetEvictionPolicy to be used to specify eviction policy for low priority virtual machine scale set. Default to Delete.")] - [PSArgumentCompleter("Delete", "Deallocate")] - public string NodeScaleSetEvictionPolicy { get; set; } - - [Parameter(Mandatory = false, HelpMessage = "Add-on names to be enabled when cluster is created.")] - [ValidateNotNullOrEmpty()] - [PSArgumentCompleter("HttpApplicationRouting", "Monitoring", "VirtualNode", "AzurePolicy", "KubeDashboard")] - public string[] AddOnNameToBeEnabled { get; set; } - - [Parameter(Mandatory = false, - ValueFromPipelineByPropertyName = true, - HelpMessage = "Resource Id of the workspace of Monitoring addon.")] - [ValidateNotNullOrEmpty] - public string WorkspaceResourceId { get; set; } - - [Parameter(Mandatory = false, - ValueFromPipelineByPropertyName = true, - HelpMessage = "Subnet name of VirtualNode addon.")] - [ValidateNotNullOrEmpty] - public string SubnetName { get; set; } - - ///// The client AAD application ID. - //[Parameter(Mandatory = false, HelpMessage = "The client AAD application ID.")] - //public string AadProfileClientAppId { get; set; } - - ///// The server AAD application ID. - //[Parameter(Mandatory = false, HelpMessage = "The server AAD application ID.")] - //public string AadProfileServerAppId { get; set; } - - ///// The server AAD application secret. - //[Parameter(Mandatory = false, HelpMessage = "The server AAD application secret.")] - //public string AadProfileServerAppSecret { get; set; } - - //// The AAD tenant ID to use for authentication. If not specified, will use the tenant of the deployment subscription. - //[Parameter(Mandatory = false, - // HelpMessage = - // "The AAD tenant ID to use for authentication. If not specified, will use the tenant of the deployment subscription.")] - //public string AadProfileTenantId { get; set; } - - ///// Profile of managed cluster add-on. - //[Parameter(Mandatory = false, HelpMessage = "Profile of managed cluster add-on.")] - //public ManagedClusterAddonProfile AddOnProfile { get; set; } - - [Parameter(Mandatory = false, HelpMessage = "Grant the 'acrpull' role of the specified ACR to AKS Service Principal, e.g. myacr")] - public string AcrNameToAttach { get; set; } - - [Parameter(Mandatory = false, HelpMessage = "Whether to enable Kubernetes Role-Based Access")] - public SwitchParameter EnableRbac { get; set; } - - ////Hide it as there's no GA plan for it. - //[Parameter(Mandatory = false, HelpMessage = "Whether to enable Kubernetes Pod security")] - //public SwitchParameter EnablePodSecurityPolicy { get; set; } - - [Parameter(Mandatory = false, HelpMessage = "The administrator username to use for Windows VMs.")] - public string WindowsProfileAdminUserName { get; set; } - - [Parameter(Mandatory = false, HelpMessage = "The administrator password to use for Windows VMs. Password requirement:" - + "At least one lower case, one upper case, one special character !@#$%^&*(), the minimum lenth is 12.")] - [ValidateSecureString(RegularExpression = "^(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%\\^&\\*\\(\\)])[a-zA-Z\\d!@#$%\\^&\\*\\(\\)]{12,123}$", ParameterName = nameof(WindowsProfileAdminUserPassword))] - public SecureString WindowsProfileAdminUserPassword { get; set; } - - [Parameter(Mandatory = false, HelpMessage = "Network plugin used for building Kubernetes network.")] - [PSArgumentCompleter("azure", "kubenet")] - public string NetworkPlugin { get; set; } = "azure"; - - [Parameter(Mandatory = false, HelpMessage = "The load balancer sku for the managed cluster.")] - [PSArgumentCompleter("basic", "standard")] - public string LoadBalancerSku { get; set; } - - protected override ManagedCluster BuildNewCluster() - { - BeforeBuildNewCluster(); - - var pubKey = - new List { new ContainerServiceSshPublicKey(SshKeyValue) }; - - var linuxProfile = - new ContainerServiceLinuxProfile(LinuxProfileAdminUserName, - new ContainerServiceSshConfiguration(pubKey)); - - var acsServicePrincipal = EnsureServicePrincipal(ServicePrincipalIdAndSecret?.UserName, ServicePrincipalIdAndSecret?.Password?.ConvertToString()); - - var spProfile = new ManagedClusterServicePrincipalProfile( - acsServicePrincipal.SpId, - acsServicePrincipal.ClientSecret); - - var aadProfile = GetAadProfile(); - - var defaultAgentPoolProfile = GetAgentPoolProfile(); - - var windowsProfile = GetWindowsProfile(); - - var networkProfile = GetNetworkProfile(); - - var addonProfiles = CreateAddonsProfiles(); - - WriteVerbose(string.Format(Resources.DeployingYourManagedKubeCluster, AcsSpFilePath)); - - var managedCluster = new ManagedCluster( - Location, - name: Name, - tags: TagsConversionHelper.CreateTagDictionary(Tag, true), - dnsPrefix: DnsNamePrefix, - kubernetesVersion: KubernetesVersion, - agentPoolProfiles: new List { defaultAgentPoolProfile }, - linuxProfile: linuxProfile, - windowsProfile: windowsProfile, - servicePrincipalProfile: spProfile, - aadProfile: aadProfile, - addonProfiles: addonProfiles, - networkProfile: networkProfile); - - if(EnableRbac.IsPresent) - { - managedCluster.EnableRBAC = EnableRbac; - } - //if(EnablePodSecurityPolicy.IsPresent) - //{ - // managedCluster.EnablePodSecurityPolicy = EnablePodSecurityPolicy; - //} - - if(this.IsParameterBound(c => c.AcrNameToAttach)) - { - AddAcrRoleAssignment(AcrNameToAttach, nameof(AcrNameToAttach), acsServicePrincipal); - } - - return managedCluster; - } - - private ContainerServiceNetworkProfile GetNetworkProfile() - { - var networkProfile = new ContainerServiceNetworkProfile(); - networkProfile.NetworkPlugin = NetworkPlugin; - networkProfile.LoadBalancerSku = LoadBalancerSku; - return networkProfile; - } - - private ManagedClusterWindowsProfile GetWindowsProfile() - { - ManagedClusterWindowsProfile windowsProfile = null; - - if(!string.IsNullOrEmpty(WindowsProfileAdminUserName) || - WindowsProfileAdminUserPassword != null) - { - windowsProfile = new ManagedClusterWindowsProfile(WindowsProfileAdminUserName, - WindowsProfileAdminUserPassword?.ConvertToString()); - } - return windowsProfile; - } - - private ManagedClusterAgentPoolProfile GetAgentPoolProfile() - { - var defaultAgentPoolProfile = new ManagedClusterAgentPoolProfile( - name: NodeName ?? "default", - count: NodeCount, - vmSize: NodeVmSize, - osDiskSizeGB: NodeOsDiskSize, - type: NodeVmSetType ?? "VirtualMachineScaleSets", - vnetSubnetID: NodeVnetSubnetID); - defaultAgentPoolProfile.OsType = "Linux"; - if (this.IsParameterBound(c => c.NodeMaxPodCount)) - { - defaultAgentPoolProfile.MaxPods = NodeMaxPodCount; - } - if (this.IsParameterBound(c => c.NodeMinCount)) - { - defaultAgentPoolProfile.MinCount = NodeMinCount; - } - if (this.IsParameterBound(c => c.NodeMaxCount)) - { - defaultAgentPoolProfile.MaxCount = NodeMaxCount; - } - if (EnableNodeAutoScaling.IsPresent) - { - defaultAgentPoolProfile.EnableAutoScaling = EnableNodeAutoScaling.ToBool(); - } - //if (EnableNodePublicIp.IsPresent) - //{ - // defaultAgentPoolProfile.EnableNodePublicIP = EnableNodePublicIp.ToBool(); - //} - if (this.IsParameterBound(c => c.NodeScaleSetEvictionPolicy)) - { - defaultAgentPoolProfile.ScaleSetEvictionPolicy = NodeScaleSetEvictionPolicy; - } - if (this.IsParameterBound(c => c.NodeSetPriority)) - { - defaultAgentPoolProfile.ScaleSetPriority = NodeSetPriority; - } - defaultAgentPoolProfile.Mode = NodePoolMode; - - return defaultAgentPoolProfile; - } - - private ManagedClusterAADProfile GetAadProfile() - { - ManagedClusterAADProfile aadProfile = null; - //if (!string.IsNullOrEmpty(AadProfileClientAppId) || !string.IsNullOrEmpty(AadProfileServerAppId) || - // !string.IsNullOrEmpty(AadProfileServerAppSecret) || !string.IsNullOrEmpty(AadProfileTenantId)) - //{ - // aadProfile = new ManagedClusterAADProfile(clientAppID: AadProfileClientAppId, serverAppID: AadProfileServerAppId, - // serverAppSecret: AadProfileServerAppSecret, tenantID: AadProfileTenantId); - //} - return aadProfile; - } - - private IDictionary CreateAddonsProfiles() - { - if (this.IsParameterBound(c => c.AddOnNameToBeEnabled)) - { - Dictionary addonProfiles = new Dictionary(); - return AddonUtils.EnableAddonsProfile(addonProfiles, AddOnNameToBeEnabled, nameof(AddOnNameToBeEnabled), WorkspaceResourceId, nameof(WorkspaceResourceId), SubnetName, nameof(SubnetName)); - } else - { - return null; - } - } - } -} \ No newline at end of file diff --git a/src/Aks/Aks/Commands/SetAzureRmAks.cs b/src/Aks/Aks/Commands/SetAzureRmAks.cs index 9c08152c3bff..d9cf59dc5d56 100644 --- a/src/Aks/Aks/Commands/SetAzureRmAks.cs +++ b/src/Aks/Aks/Commands/SetAzureRmAks.cs @@ -12,6 +12,7 @@ // limitations under the License. // ---------------------------------------------------------------------------------- +using System; using System.Collections.Generic; using System.Linq; using System.Management.Automation; @@ -21,9 +22,16 @@ using Microsoft.Azure.Commands.Common.Exceptions; using Microsoft.Azure.Commands.ResourceManager.Common.ArgumentCompleters; using Microsoft.Azure.Commands.ResourceManager.Common.Tags; +using Microsoft.Azure.Graph.RBAC.Version1_6; +using Microsoft.Azure.Graph.RBAC.Version1_6.Models; +using Microsoft.Azure.Management.Authorization.Version2015_07_01; +using Microsoft.Azure.Management.Authorization.Version2015_07_01.Models; using Microsoft.Azure.Management.ContainerService; using Microsoft.Azure.Management.ContainerService.Models; +using Microsoft.Azure.Management.Internal.Resources; +using Microsoft.Azure.Management.Internal.Resources.Models; using Microsoft.Azure.Management.Internal.Resources.Utilities.Models; +using Microsoft.Rest.Azure.OData; using Microsoft.WindowsAzure.Commands.Common; using Microsoft.WindowsAzure.Commands.Common.CustomAttributes; using Microsoft.WindowsAzure.Commands.Utilities.Common; @@ -50,6 +58,9 @@ public class SetAzureRmAks : CreateOrUpdateKubeBase [PSArgumentCompleter("System", "User")] public string NodePoolMode { get; set; } + [Parameter(Mandatory = false, HelpMessage = "Disable the 'acrpull' role assignment to the ACR specified by name or resource ID, e.g. myacr")] + public string AcrNameToDetach { get; set; } + /// /// Cluster name /// @@ -62,6 +73,55 @@ public class SetAzureRmAks : CreateOrUpdateKubeBase [Alias("ResourceId")] public string Id { get; set; } + private ManagedCluster BuildNewCluster() + { + BeforeBuildNewCluster(); + + var defaultAgentPoolProfile = new ManagedClusterAgentPoolProfile( + name: NodeName ?? "default", + count: NodeCount, + vmSize: NodeVmSize, + osDiskSizeGB: NodeOsDiskSize); + + if (this.IsParameterBound(c => c.NodeMinCount)) + { + defaultAgentPoolProfile.MinCount = NodeMinCount; + } + if (this.IsParameterBound(c => c.NodeMaxCount)) + { + defaultAgentPoolProfile.MaxCount = NodeMaxCount; + } + if (EnableNodeAutoScaling.IsPresent) + { + defaultAgentPoolProfile.EnableAutoScaling = EnableNodeAutoScaling.ToBool(); + } + + var pubKey = + new List { new ContainerServiceSshPublicKey(SshKeyValue) }; + + var linuxProfile = + new ContainerServiceLinuxProfile(LinuxProfileAdminUserName, + new ContainerServiceSshConfiguration(pubKey)); + + var acsServicePrincipal = EnsureServicePrincipal(ServicePrincipalIdAndSecret?.UserName, ServicePrincipalIdAndSecret?.Password?.ConvertToString()); + + var spProfile = new ManagedClusterServicePrincipalProfile( + acsServicePrincipal.SpId, + acsServicePrincipal.ClientSecret); + + WriteVerbose(string.Format(Resources.DeployingYourManagedKubeCluster, AcsSpFilePath)); + var managedCluster = new ManagedCluster( + Location, + name: Name, + tags: TagsConversionHelper.CreateTagDictionary(Tag, true), + dnsPrefix: DnsNamePrefix, + kubernetesVersion: KubernetesVersion, + agentPoolProfiles: new List { defaultAgentPoolProfile }, + linuxProfile: linuxProfile, + servicePrincipalProfile: spProfile); + return managedCluster; + } + public override void ExecuteCmdlet() { base.ExecuteCmdlet(); @@ -93,6 +153,7 @@ public override void ExecuteCmdlet() { RunCmdLet(() => { + AcsServicePrincipal acsServicePrincipal; if (Exists()) { if (cluster == null) @@ -125,7 +186,7 @@ public override void ExecuteCmdlet() if (this.IsParameterBound(c => c.ServicePrincipalIdAndSecret)) { WriteVerbose(Resources.UpdatingServicePrincipal); - var acsServicePrincipal = EnsureServicePrincipal(ServicePrincipalIdAndSecret.UserName, ServicePrincipalIdAndSecret.Password?.ConvertToString()); + acsServicePrincipal = EnsureServicePrincipal(ServicePrincipalIdAndSecret.UserName, ServicePrincipalIdAndSecret.Password?.ConvertToString()); var spProfile = new ManagedClusterServicePrincipalProfile( acsServicePrincipal.SpId, @@ -228,11 +289,57 @@ public override void ExecuteCmdlet() cluster = BuildNewCluster(); } + acsServicePrincipal = EnsureServicePrincipal(ServicePrincipalIdAndSecret?.UserName, ServicePrincipalIdAndSecret?.Password?.ConvertToString()); + if (this.IsParameterBound(c => c.AcrNameToAttach)) + { + AddAcrRoleAssignment(AcrNameToAttach, nameof(AcrNameToAttach), acsServicePrincipal); + } + if (this.IsParameterBound(c => c.AcrNameToDetach)) + { + RemoveAcrRoleAssignment(AcrNameToDetach, nameof(AcrNameToDetach), acsServicePrincipal); + } + var kubeCluster = Client.ManagedClusters.CreateOrUpdate(ResourceGroupName, Name, cluster); + WriteObject(PSMapper.Instance.Map(kubeCluster)); }); } } + private void RemoveAcrRoleAssignment(string acrName, string acrParameterName, AcsServicePrincipal acsServicePrincipal) + { + string acrResourceId = null; + try + { + //Find Acr resourceId first + var acrQuery = new ODataQuery($"$filter=resourceType eq 'Microsoft.ContainerRegistry/registries' and name eq '{acrName}'"); + var acrObjects = RmClient.Resources.List(acrQuery); + acrResourceId = acrObjects.First().Id; + } + catch (Exception) + { + throw new AzPSArgumentException( + string.Format(Resources.CouldNotFindSpecifiedAcr, acrName), + acrParameterName, + string.Format(Resources.CouldNotFindSpecifiedAcr, "*")); + } + + var roleDefinitionId = GetRoleId("acrpull", acrResourceId); + RoleAssignment roleAssignment = GetRoleAssignmentWithRoleDefinitionId(roleDefinitionId); + if (roleAssignment == null) + { + throw new AzPSInvalidOperationException( + Resources.CouldNotDeleteAcrRoleAssignment, + desensitizedMessage: Resources.CouldNotDeleteAcrRoleAssignment); + } + + var deleteResult = RetryAction(() => AuthClient.RoleAssignments.DeleteById(roleAssignment.Id)); + if (!deleteResult) + { + throw new AzPSInvalidOperationException( + Resources.CouldNotDeleteAcrRoleAssignment, + desensitizedMessage: Resources.CouldNotDeleteAcrRoleAssignment); + } + } private bool NeedUpdateNodeAgentPool() { diff --git a/src/Aks/Aks/Properties/Resources.Designer.cs b/src/Aks/Aks/Properties/Resources.Designer.cs index 81bd3b495ee5..c9dc1e4dc63a 100644 --- a/src/Aks/Aks/Properties/Resources.Designer.cs +++ b/src/Aks/Aks/Properties/Resources.Designer.cs @@ -60,6 +60,15 @@ internal Resources() { } } + /// + /// Looks up a localized string similar to Acr role assignment {0} is already exist.. + /// + internal static string AcrRoleAssignmentIsAlreadyExist { + get { + return ResourceManager.GetString("AcrRoleAssignmentIsAlreadyExist", resourceCulture); + } + } + /// /// Looks up a localized string similar to Please add {0} to your search PATH so the {1} can be found.. /// @@ -231,6 +240,15 @@ internal static string CouldNotCreateAServicePrincipalWithTheRightPermissionsAre } } + /// + /// Looks up a localized string similar to Could not delete 'acrpull' role assignment, please make sure you have right permission.. + /// + internal static string CouldNotDeleteAcrRoleAssignment { + get { + return ResourceManager.GetString("CouldNotDeleteAcrRoleAssignment", resourceCulture); + } + } + /// /// Looks up a localized string similar to Could not find object id of service principal : {0}, please make sure you have graph directory.read permission which is required for grant acrpull permission.. /// @@ -258,6 +276,15 @@ internal static string CouldNotFindSshPublicKeyInError { } } + /// + /// Looks up a localized string similar to Could not get 'acrpull' role assignment, please make sure you have right permission.. + /// + internal static string CouldNotGetAcrRoleAssignment { + get { + return ResourceManager.GetString("CouldNotGetAcrRoleAssignment", resourceCulture); + } + } + /// /// Looks up a localized string similar to Created a new Service Principal and assigned the contributor role for this subscription.. /// diff --git a/src/Aks/Aks/Properties/Resources.resx b/src/Aks/Aks/Properties/Resources.resx index 036b135f2516..e85a4bcff026 100644 --- a/src/Aks/Aks/Properties/Resources.resx +++ b/src/Aks/Aks/Properties/Resources.resx @@ -411,6 +411,15 @@ Could not assign subscription contributor permission to service principal just created. Please make sure you have permission to assign subscription contributor role, or you could use parameter -ClientIdAndSecret to specify one existing service principal id and secret. + + Could not delete 'acrpull' role assignment, please make sure you have right permission. + + + Could not get 'acrpull' role assignment, please make sure you have right permission. + + + Acr role assignment {0} is already exist. + Reseting the credential of the aks cluster. diff --git a/src/Aks/Aks/help/New-AzAksCluster.md b/src/Aks/Aks/help/New-AzAksCluster.md index 0bc721e45664..3446ff1196dc 100644 --- a/src/Aks/Aks/help/New-AzAksCluster.md +++ b/src/Aks/Aks/help/New-AzAksCluster.md @@ -13,16 +13,16 @@ Create a new managed Kubernetes cluster. ## SYNTAX ``` -New-AzAksCluster [-Force] [-GenerateSshKey] [-NodeVmSetType ] [-NodeVnetSubnetID ] - [-NodeMaxPodCount ] [-NodeSetPriority ] [-NodePoolMode ] - [-NodeScaleSetEvictionPolicy ] [-AddOnNameToBeEnabled ] [-WorkspaceResourceId ] - [-SubnetName ] [-AcrNameToAttach ] [-EnableRbac] [-WindowsProfileAdminUserName ] - [-WindowsProfileAdminUserPassword ] [-NetworkPlugin ] [-LoadBalancerSku ] - [-ResourceGroupName] [-Name] [[-ServicePrincipalIdAndSecret] ] - [-Location ] [-LinuxProfileAdminUserName ] [-DnsNamePrefix ] - [-KubernetesVersion ] [-NodeName ] [-NodeMinCount ] [-NodeMaxCount ] - [-EnableNodeAutoScaling] [-NodeCount ] [-NodeOsDiskSize ] [-NodeVmSize ] - [-SshKeyValue ] [-AsJob] [-Tag ] [-DefaultProfile ] [-WhatIf] +New-AzAksCluster [-NodeVmSetType ] [-NodeVnetSubnetID ] [-NodeMaxPodCount ] + [-NodeSetPriority ] [-NodePoolMode ] [-NodeScaleSetEvictionPolicy ] + [-AddOnNameToBeEnabled ] [-WorkspaceResourceId ] [-SubnetName ] [-EnableRbac] + [-WindowsProfileAdminUserName ] [-WindowsProfileAdminUserPassword ] + [-NetworkPlugin ] [-LoadBalancerSku ] [-Force] [-GenerateSshKey] [-ResourceGroupName] + [-Name] [[-ServicePrincipalIdAndSecret] ] [-Location ] + [-LinuxProfileAdminUserName ] [-DnsNamePrefix ] [-KubernetesVersion ] + [-NodeName ] [-NodeMinCount ] [-NodeMaxCount ] [-EnableNodeAutoScaling] + [-NodeCount ] [-NodeOsDiskSize ] [-NodeVmSize ] [-SshKeyValue ] + [-AcrNameToAttach ] [-AsJob] [-Tag ] [-DefaultProfile ] [-WhatIf] [-Confirm] [] ``` diff --git a/src/Aks/Aks/help/Set-AzAksCluster.md b/src/Aks/Aks/help/Set-AzAksCluster.md index 59b8529e1f01..9fd3ebf5574c 100644 --- a/src/Aks/Aks/help/Set-AzAksCluster.md +++ b/src/Aks/Aks/help/Set-AzAksCluster.md @@ -14,30 +14,33 @@ Update or create a managed Kubernetes cluster. ### defaultParameterSet (Default) ``` -Set-AzAksCluster [-NodePoolMode ] [-ResourceGroupName] [-Name] - [[-ServicePrincipalIdAndSecret] ] [-Location ] [-LinuxProfileAdminUserName ] - [-DnsNamePrefix ] [-KubernetesVersion ] [-NodeName ] [-NodeMinCount ] - [-NodeMaxCount ] [-EnableNodeAutoScaling] [-NodeCount ] [-NodeOsDiskSize ] - [-NodeVmSize ] [-SshKeyValue ] [-AsJob] [-Tag ] - [-DefaultProfile ] [-WhatIf] [-Confirm] [] +Set-AzAksCluster [-NodePoolMode ] [-AcrNameToDetach ] [-ResourceGroupName] + [-Name] [[-ServicePrincipalIdAndSecret] ] [-Location ] + [-LinuxProfileAdminUserName ] [-DnsNamePrefix ] [-KubernetesVersion ] + [-NodeName ] [-NodeMinCount ] [-NodeMaxCount ] [-EnableNodeAutoScaling] + [-NodeCount ] [-NodeOsDiskSize ] [-NodeVmSize ] [-SshKeyValue ] + [-AcrNameToAttach ] [-AsJob] [-Tag ] [-DefaultProfile ] [-WhatIf] + [-Confirm] [] ``` ### InputObjectParameterSet ``` -Set-AzAksCluster -InputObject [-NodePoolMode ] [-Location ] - [-LinuxProfileAdminUserName ] [-DnsNamePrefix ] [-KubernetesVersion ] - [-NodeName ] [-NodeMinCount ] [-NodeMaxCount ] [-EnableNodeAutoScaling] - [-NodeCount ] [-NodeOsDiskSize ] [-NodeVmSize ] [-SshKeyValue ] [-AsJob] - [-Tag ] [-DefaultProfile ] [-WhatIf] [-Confirm] [] +Set-AzAksCluster -InputObject [-NodePoolMode ] [-AcrNameToDetach ] + [-Location ] [-LinuxProfileAdminUserName ] [-DnsNamePrefix ] + [-KubernetesVersion ] [-NodeName ] [-NodeMinCount ] [-NodeMaxCount ] + [-EnableNodeAutoScaling] [-NodeCount ] [-NodeOsDiskSize ] [-NodeVmSize ] + [-SshKeyValue ] [-AcrNameToAttach ] [-AsJob] [-Tag ] + [-DefaultProfile ] [-WhatIf] [-Confirm] [] ``` ### IdParameterSet ``` -Set-AzAksCluster [-NodePoolMode ] [-Id] [-Location ] +Set-AzAksCluster [-NodePoolMode ] [-AcrNameToDetach ] [-Id] [-Location ] [-LinuxProfileAdminUserName ] [-DnsNamePrefix ] [-KubernetesVersion ] [-NodeName ] [-NodeMinCount ] [-NodeMaxCount ] [-EnableNodeAutoScaling] - [-NodeCount ] [-NodeOsDiskSize ] [-NodeVmSize ] [-SshKeyValue ] [-AsJob] - [-Tag ] [-DefaultProfile ] [-WhatIf] [-Confirm] [] + [-NodeCount ] [-NodeOsDiskSize ] [-NodeVmSize ] [-SshKeyValue ] + [-AcrNameToAttach ] [-AsJob] [-Tag ] [-DefaultProfile ] [-WhatIf] + [-Confirm] [] ``` ## DESCRIPTION @@ -54,6 +57,36 @@ Set the number of nodes in the Kubernetes cluster to 5. ## PARAMETERS +### -AcrNameToAttach +Grant the 'acrpull' role of the specified ACR to AKS Service Principal, e.g. myacr + +```yaml +Type: System.String +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -AcrNameToDetach +Disable the 'acrpull' role assignment to the ACR specified by name or resource ID, e.g. myacr + +```yaml +Type: System.String +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -AsJob Run cmdlet in the background