Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public string Uri
get { return this._uri; }
set { this._uri = value; }
}

/// <summary>
/// Initializes a new instance of the EncryptionProtectorProperties
/// class.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public void TestDatabaseTransparentDataEncryptionGet()
RunPowerShellTest("Test-GetTransparentDataEncryption");
}

[Fact]
[Fact(Skip = "TODO: Skipping as the model got updated from Legacy Sdk")]
[Trait(Category.AcceptanceType, Category.CheckIn)]
public void TestServerTransparentDataEncryptionProtectorGet()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,3 +154,41 @@ function Test-SetTransparentDataEncryptionProtector
Remove-ResourceGroupForTest $rg
}
}

<#
.SYNOPSIS
Tests Setting a server transparent data encryption protector
#>
function Test-SetTransparentDataEncryptionProtectorWithKeyRotation
{
# Setup
$params = Get-SqlServerKeyVaultKeyTestEnvironmentParameters
$rg = Create-ServerKeyVaultKeyTestEnvironment $params
$autoRotationEnabled = $true

try
{
# Encryption Protector should be set to Service Managed initially
$encProtector1 = Get-AzSqlServerTransparentDataEncryptionProtector -ResourceGroupName $params.rgName -ServerName $params.serverName
Assert-AreEqual ServiceManaged $encProtector1.Type
Assert-AreEqual ServiceManaged $encProtector1.ServerKeyVaultKeyName

# Add server key
$keyResult = Add-AzSqlServerKeyVaultKey -ServerName $params.serverName -ResourceGroupName $params.rgName -KeyId $params.keyId
Assert-AreEqual $params.keyId $keyResult.Uri

# Rotate to AKV
$job = Set-AzSqlServerTransparentDataEncryptionProtector -ResourceGroupName $params.rgName -ServerName $params.serverName `
-Type AzureKeyVault -KeyId $params.keyId -AutoRotationEnabled $autoRotationEnabled -Force -AsJob
$job | Wait-Job
$encProtector2 = $job.Output

Assert-AreEqual AzureKeyVault $encProtector2.Type
Assert-AreEqual $params.serverKeyName $encProtector2.ServerKeyVaultKeyName
Assert-AreEqual $autoRotationEnabled $encProtector2.AutoRotationEnabled
}
finally
{
Remove-ResourceGroupForTest $rg
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ public DiagnosticSettingsResource UpdateDiagnosticSettings(DiagnosticSettingsRes
if (server.Identity == null ||
server.Identity.Type != ResourceIdentityType.SystemAssigned.ToString())
{
server.Identity = ResourceIdentityHelper.GetIdentityObjectFromType(true);
server.Identity = ResourceIdentityHelper.GetIdentityObjectFromType(true, "SystemAssigned", null, null);
server = GetCurrentSqlClient().Servers.CreateOrUpdate(resourceGroupName, serverName, server);
}

Expand Down
116 changes: 112 additions & 4 deletions src/Sql/Sql/Common/ResourceIdentityHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,27 +12,135 @@
// limitations under the License.
// ----------------------------------------------------------------------------------

using Microsoft.Azure.Management.Sql.Models;
using System.Collections.Generic;
using System.Linq;
using System.Management.Automation;
using System.Runtime.CompilerServices;

namespace Microsoft.Azure.Commands.Sql.Common
{
public enum ResourceIdentityType
{
SystemAssigned
SystemAssigned,
SystemAssignedUserAssigned,
UserAssigned,
None
}

public class ResourceIdentityHelper
{
public static Management.Sql.Models.ResourceIdentity GetIdentityObjectFromType(bool assignIdentityIsPresent)
public static Management.Sql.Models.ResourceIdentity GetIdentityObjectFromType(bool assignIdentityIsPresent, string resourceIdentityType, List<string> userAssignedIdentities, Management.Sql.Models.ResourceIdentity existingResourceIdentity)
{
Management.Sql.Models.ResourceIdentity identityResult = null;
if (assignIdentityIsPresent)

// If the user passes in IdentityType as None, then irrespective of previous config, we set the IdentityType to be None.
//
if (resourceIdentityType != null && resourceIdentityType.Equals(ResourceIdentityType.None.ToString()))
{
identityResult = new Management.Sql.Models.ResourceIdentity()
{
Type = ResourceIdentityType.SystemAssigned.ToString()
Type = ResourceIdentityType.None.ToString()
};

return identityResult;
}

if (resourceIdentityType != null && assignIdentityIsPresent && resourceIdentityType.Equals(ResourceIdentityType.SystemAssignedUserAssigned.ToString()))
{
Dictionary<string, UserIdentity> umiDict = new Dictionary<string, UserIdentity>();

if (userAssignedIdentities == null)
{
throw new PSArgumentNullException("The list of user assigned identity ids needs to be passed if the IdentityType is UserAssigned or SystemAssignedUserAssigned");
}

if (existingResourceIdentity != null && userAssignedIdentities.Any()
&& existingResourceIdentity.UserAssignedIdentities != null)
{
foreach (string identity in userAssignedIdentities)
{
existingResourceIdentity.UserAssignedIdentities.Add(identity, new UserIdentity());
}

identityResult = new Management.Sql.Models.ResourceIdentity()
{
Type = ResourceIdentityType.SystemAssignedUserAssigned.ToString()
};
}
else if (userAssignedIdentities.Any())
{
foreach (string identity in userAssignedIdentities)
{
umiDict.Add(identity, new UserIdentity());
}

identityResult = new Management.Sql.Models.ResourceIdentity()
{
Type = ResourceIdentityType.SystemAssignedUserAssigned.ToString(),
UserAssignedIdentities = umiDict
};
}
}
else if (resourceIdentityType != null && assignIdentityIsPresent && resourceIdentityType.Equals(ResourceIdentityType.UserAssigned.ToString()))
{
Dictionary<string, UserIdentity> umiDict = new Dictionary<string, UserIdentity>();

if (userAssignedIdentities == null)
{
throw new PSArgumentNullException("The list of user assigned identity ids needs to be passed if the IdentityType is UserAssigned or SystemAssignedUserAssigned");
}

if (existingResourceIdentity != null && userAssignedIdentities.Any()
&& existingResourceIdentity.UserAssignedIdentities != null)
{
foreach (string identity in userAssignedIdentities)
{
existingResourceIdentity.UserAssignedIdentities.Add(identity, new UserIdentity());
}

identityResult = new Management.Sql.Models.ResourceIdentity()
{
Type = ResourceIdentityType.UserAssigned.ToString()
};
}
else if (userAssignedIdentities.Any())
{
foreach (string identity in userAssignedIdentities)
{
umiDict.Add(identity, new UserIdentity());
}

identityResult = new Management.Sql.Models.ResourceIdentity()
{
Type = ResourceIdentityType.UserAssigned.ToString(),
UserAssignedIdentities = umiDict
};
}
}
else if (assignIdentityIsPresent)
{
if (existingResourceIdentity != null)
{
identityResult = existingResourceIdentity;
identityResult.Type = ResourceIdentityType.SystemAssigned.ToString();
}
else
{
identityResult = new Management.Sql.Models.ResourceIdentity()
{
Type = ResourceIdentityType.SystemAssigned.ToString()
};
}
}

if (!assignIdentityIsPresent && existingResourceIdentity != null && existingResourceIdentity.PrincipalId != null)
{
identityResult = existingResourceIdentity;
}

return identityResult;

}
}
}
33 changes: 32 additions & 1 deletion src/Sql/Sql/ManagedInstance/Cmdlet/NewAzureSqlManagedInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,35 @@ public class NewAzureSqlManagedInstance : ManagedInstanceCmdletBase
HelpMessage = "The Maintenance configuration id for the Sql Azure Managed Instance.")]
public string MaintenanceConfigurationId { get; set; }

/// <summary>
/// Id of the primary user assigned identity
/// </summary>
[Parameter(Mandatory = false,
HelpMessage = "The primary user managed identity(UMI) id")]
public string PrimaryUserAssignedIdentityId { get; set; }

/// <summary>
/// URI of the key to use for encryption
/// </summary>
[Parameter(Mandatory = false,
HelpMessage = "The Key Vault URI for encryption")]
public string KeyId { get; set; }

// <summary>
/// List of user assigned identities.
/// </summary>
[Parameter(Mandatory = false,
HelpMessage = "List of user assigned identities")]
public List<string> UserAssignedIdentityId { get; set; }

// <summary>
/// Type of identity to be assigned to the server..
/// </summary>
[Parameter(Mandatory = false,
HelpMessage = "Type of Identity to be used. Possible values are SystemAsssigned, UserAssigned, SystemAssignedUserAssigned and None.")]
[PSArgumentCompleter("SystemAssigned", "UserAssigned", "SystemAssignedUserAssigned", "None")]
public string IdentityType { get; set; }

/// <summary>
/// Gets or sets whether or not to run this cmdlet in the background as a job
/// </summary>
Expand Down Expand Up @@ -496,7 +525,7 @@ public override void ExecuteCmdlet()
AdministratorPassword = (this.AdministratorCredential != null) ? this.AdministratorCredential.Password : null,
AdministratorLogin = (this.AdministratorCredential != null) ? this.AdministratorCredential.UserName : null,
Tags = TagsConversionHelper.CreateTagDictionary(Tag, validate: true),
Identity = ResourceIdentityHelper.GetIdentityObjectFromType(this.AssignIdentity.IsPresent),
Identity = ResourceIdentityHelper.GetIdentityObjectFromType(this.AssignIdentity.IsPresent, this.IdentityType ?? null, UserAssignedIdentityId, null),
LicenseType = this.LicenseType,
// `-StorageSizeInGB 0` as a parameter to this cmdlet means "use default".
// For non-MI database, we can just pass in 0 and the server will treat 0 as default.
Expand All @@ -515,6 +544,8 @@ public override void ExecuteCmdlet()
MinimalTlsVersion = this.MinimalTlsVersion,
BackupStorageRedundancy = this.BackupStorageRedundancy,
MaintenanceConfigurationId = this.MaintenanceConfigurationId,
PrimaryUserAssignedIdentityId = this.PrimaryUserAssignedIdentityId,
KeyId = this.KeyId,
Administrators = new Management.Sql.Models.ManagedInstanceExternalAdministrator()
{
AzureADOnlyAuthentication = (this.EnableActiveDirectoryOnlyAuthentication.IsPresent) ? (bool?)true : null,
Expand Down
35 changes: 33 additions & 2 deletions src/Sql/Sql/ManagedInstance/Cmdlet/SetAzureSqlManagedInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,20 @@ public class SetAzureSqlManagedInstance : ManagedInstanceCmdletBase
[PSArgumentCompleter("None", "1.0", "1.1", "1.2")]
public string MinimalTlsVersion { get; set; }

/// <summary>
/// Id of the primary user assigned identity
/// </summary>
[Parameter(Mandatory = false,
HelpMessage = "The primary user managed identity(UMI) id")]
public string PrimaryUserAssignedIdentityId { get; set; }

/// <summary>
/// URI of the key to use for encryption
/// </summary>
[Parameter(Mandatory = false,
HelpMessage = "The Key Vault URI for encryption")]
public string KeyId { get; set; }

/// <summary>
/// Defines whether it is ok to skip the requesting of rule removal confirmation
/// </summary>
Expand All @@ -204,6 +218,21 @@ public class SetAzureSqlManagedInstance : ManagedInstanceCmdletBase
HelpMessage = "The Maintenance configuration id for the Sql Azure Managed Instance.")]
public string MaintenanceConfigurationId { get; set; }

// <summary>
/// List of user assigned identities.
/// </summary>
[Parameter(Mandatory = false,
HelpMessage = "List of user assigned identities")]
public List<string> UserAssignedIdentityId { get; set; }

// <summary>
/// List of user assigned identities.
/// </summary>
[Parameter(Mandatory = false,
HelpMessage = "Type of Identity to be used. Possible values are SystemAsssigned, UserAssigned, SystemAssignedUserAssigned and None.")]
[PSArgumentCompleter("SystemAssigned", "UserAssigned", "SystemAssignedUserAssigned", "None")]
public string IdentityType { get; set; }

/// <summary>
/// Gets or sets whether or not to run this cmdlet in the background as a job
/// </summary>
Expand Down Expand Up @@ -287,11 +316,13 @@ protected override IEnumerable<AzureSqlManagedInstanceModel> ApplyUserInputToMod
PublicDataEndpointEnabled = this.PublicDataEndpointEnabled,
ProxyOverride = this.ProxyOverride,
Tags = TagsConversionHelper.CreateTagDictionary(Tag, validate: true),
Identity = model.FirstOrDefault().Identity ?? ResourceIdentityHelper.GetIdentityObjectFromType(this.AssignIdentity.IsPresent),
Identity = ResourceIdentityHelper.GetIdentityObjectFromType(this.AssignIdentity.IsPresent, this.IdentityType ?? null, UserAssignedIdentityId, model.FirstOrDefault().Identity),
InstancePoolName = this.InstancePoolName,
MinimalTlsVersion = this.MinimalTlsVersion,
MaintenanceConfigurationId = this.MaintenanceConfigurationId,
AdministratorLogin = model.FirstOrDefault().AdministratorLogin
AdministratorLogin = model.FirstOrDefault().AdministratorLogin,
PrimaryUserAssignedIdentityId = this.PrimaryUserAssignedIdentityId ?? model.FirstOrDefault().PrimaryUserAssignedIdentityId,
KeyId = this.KeyId
});
return updateData;
}
Expand Down
10 changes: 10 additions & 0 deletions src/Sql/Sql/ManagedInstance/Model/AzureSqlManagedInstanceModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -149,5 +149,15 @@ public class AzureSqlManagedInstanceModel
/// Gets or sets the Azure SQL Managed Instance Active Directory administrator
/// </summary>
public Management.Sql.Models.ManagedInstanceExternalAdministrator Administrators { get; set; }

/// <summary>
/// Gets or sets the resource id of a user assigned identity to be used
/// </summary>
public string PrimaryUserAssignedIdentityId { get; set; }

/// <summary>
/// Gets or sets a CMK URI of the key to use for encryption.
/// </summary>
public string KeyId { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,9 @@ public AzureSqlManagedInstanceModel UpsertManagedInstance(AzureSqlManagedInstanc
MinimalTlsVersion = model.MinimalTlsVersion,
StorageAccountType = MapExternalBackupStorageRedundancyToInternal(model.BackupStorageRedundancy),
MaintenanceConfigurationId = MaintenanceConfigurationHelper.ConvertMaintenanceConfigurationIdArgument(model.MaintenanceConfigurationId, Context.Subscription.Id),
Administrators = GetActiveDirectoryInformation(model.Administrators)
Administrators = GetActiveDirectoryInformation(model.Administrators),
PrimaryUserAssignedIdentityId = model.PrimaryUserAssignedIdentityId,
KeyId = model.KeyId
});

return CreateManagedInstanceModelFromResponse(resp);
Expand Down
Loading