Skip to content
Merged
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
236 changes: 235 additions & 1 deletion AzFilesHybrid/AzFilesHybrid/AzFilesHybrid.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -3310,6 +3310,9 @@ function Debug-KerberosTicketEncryption
$kerberosTicketEncryptionClient = $kerberosTicketEncryptionClient.Value.ToString().replace(' ', '') -split ','
}

$registrySupportedEncryptionTypes = (Get-ClientSupportedEncryptionTypes).EncryptionTypes
$registrySupportedEncryptionTypes = $registrySupportedEncryptionTypes | ForEach-Object { $_ -replace '-', '' }
$kerberosTicketEncryptionClient = $registrySupportedEncryptionTypes | Where-Object { $kerberosTicketEncryptionClient -contains $_ }

$kerberosTicketEncryptionServer = $protocolSettings.KerberosTicketEncryption
if($null -eq $kerberosTicketEncryptionServer)
Expand Down Expand Up @@ -3340,6 +3343,166 @@ function Debug-KerberosTicketEncryption
}
}

function Get-ClientSupportedEncryptionTypes {
<#
.SYNOPSIS
Get the Kerberos supported encryption types enabled on the client machine from the Windows registry.

.DESCRIPTION
This cmdlet reads the SupportedEncryptionTypes registry value from the Kerberos Parameters key
and decodes it into human-readable encryption type names. The registry key is located at:
HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\Kerberos\Parameters\SupportedEncryptionTypes

The value is a DWORD bitmask where:
- Bit 0 (0x1): DES-CBC-CRC
- Bit 1 (0x2): DES-CBC-MD5
- Bit 2 (0x4): RC4-HMAC
- Bit 3 (0x8): AES128-CTS-HMAC-SHA1-96 (AES-128)
- Bit 4 (0x10): AES256-CTS-HMAC-SHA1-96 (AES-256)

If the registry key doesn't exist, Windows defaults to RC4-HMAC and AES encryption types.

.OUTPUTS
PSCustomObject with the following properties:
- RawValue: The raw DWORD value from registry (or $null if not set)
- EncryptionTypes: Array of encryption type names enabled
- SupportsAES256: Boolean indicating if AES-256 is supported
- SupportsAES128: Boolean indicating if AES-128 is supported
- SupportsRC4: Boolean indicating if RC4-HMAC is supported

.EXAMPLE
PS> Get-ClientSupportedEncryptionTypes

RawValue : 28
EncryptionTypes : {RC4-HMAC, AES-128, AES-256}
SupportsAES256 : True
SupportsAES128 : True
SupportsRC4 : True
#>

[CmdletBinding()]
param()

process {
Assert-IsWindows

$registryPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\Kerberos\Parameters"
$registryValueName = "SupportedEncryptionTypes"

# Encryption type flags as defined by Microsoft
$encryptionTypeFlags = @{
0x1 = "DES-CBC-CRC"
0x2 = "DES-CBC-MD5"
0x4 = "RC4-HMAC"
0x8 = "AES-128"
0x10 = "AES-256"
}

$rawValue = $null
$encryptionTypes = @()

Write-Verbose "Registry Path: $registryPath"
Write-Verbose "Registry Value Name: $registryValueName"
$regValue = Get-ItemProperty -Path $registryPath -Name $registryValueName -ErrorAction SilentlyContinue

if ($null -ne $regValue -and $null -ne $regValue.$registryValueName) {
$rawValue = $regValue.$registryValueName

# Decode the bitmask
foreach ($flag in $encryptionTypeFlags.Keys) {
if (($rawValue -band $flag) -eq $flag) {
$encryptionTypes += $encryptionTypeFlags[$flag]
}
}

Write-Verbose "Raw Value: $($rawValue) (0x$($rawValue.ToString('X')))"
Write-Verbose "Supported Types: $($encryptionTypes -join ', ')"
} else {
# Registry key not set - Windows defaults to RC4-HMAC, AES-128, and AES-256
Write-Verbose "SupportedEncryptionTypes registry value not found. Using Windows defaults (RC4-HMAC, AES-128, AES-256)."
$encryptionTypes = @("RC4-HMAC", "AES-128", "AES-256")
}

return [PSCustomObject]@{
RawValue = $rawValue
EncryptionTypes = $encryptionTypes
SupportsAES256 = $encryptionTypes -contains "AES-256"
SupportsAES128 = $encryptionTypes -contains "AES-128"
SupportsRC4 = $encryptionTypes -contains "RC4-HMAC"
}
}
}

function Get-ServerSupportedEncryptionTypes {
<#
.SYNOPSIS
Get the supported Authentication Methods and Kerberos supported encryption types enabled on storage account.

.DESCRIPTION
This cmdlet retrieves the supported Authentication Methods and Kerberos encryption types for a storage account.

.OUTPUTS
PSCustomObject with the following properties:
- AuthenticationMethods : Array of authentication methods supported
- SupportsKerberos : Boolean indicating if Kerberos is supported
- SupportsNTLMv2 : Boolean indicating if NTLMv2 is supported
- EncryptionTypes: Array of encryption type names enabled
- SupportsAES256: Boolean indicating if AES-256 is supported
- SupportsRC4: Boolean indicating if RC4-HMAC is supported

.EXAMPLE
PS> Get-ServerSupportedEncryptionTypes -StorageAccountName "mystorageaccount" -ResourceGroupName "myresourcegroup"

AuthenticationMethods : {Kerberos}
SupportsKerberos : True
SupportsNTLMv2 : False
EncryptionTypes : {RC4-HMAC, AES-128, AES-256}
SupportsAES256 : True
SupportsRC4 : True
#>

[CmdletBinding()]
param (
[Parameter(Mandatory=$True, Position=0, HelpMessage="Storage account name")]
[string]$StorageAccountName,

[Parameter(Mandatory=$True, Position=1, HelpMessage="Resource group name")]
[string]$ResourceGroupName
)

process {
$storageAccount = Validate-StorageAccount -ResourceGroupName $ResourceGroupName `
-StorageAccountName $StorageAccountName -ErrorAction Stop

$protocolSettings = (Get-AzStorageFileServiceProperty -StorageAccount $storageAccount -ErrorAction Stop).ProtocolSettings.Smb

$authenticationMethods = $protocolSettings.AuthenticationMethods
if ($null -eq $authenticationMethods)
{
Write-Verbose "Authentication methods are not set on the storage account. Default all types are supported."
$authenticationMethods = "NTLMv2", "Kerberos"
}
Write-Verbose "Authentication Methods supported on the server side: $($authenticationMethods -join ', ')"

$kerberosTicketEncryptionServer = $protocolSettings.KerberosTicketEncryption
if($null -eq $kerberosTicketEncryptionServer)
{
Write-Verbose "Kerberos Ticket Encryption is not set on the storage account. Default all types are supported."
$kerberosTicketEncryptionServer = "RC4-HMAC", "AES-256" # null(default): all values are accepted on the server
}
Write-Verbose "Kerberos Ticket Encryption Types supported on the server side: $($kerberosTicketEncryptionServer -join ', ')"

return [PSCustomObject]@{
Comment thread
MarcosJLR marked this conversation as resolved.
AuthenticationMethods = $authenticationMethods
SupportsKerberos = $authenticationMethods -contains "Kerberos"
SupportsNTLMv2 = $authenticationMethods -contains "NTLMv2"
EncryptionTypes = $kerberosTicketEncryptionServer
SupportsAES256 = $kerberosTicketEncryptionServer -contains "AES-256"
SupportsRC4 = $kerberosTicketEncryptionServer -contains "RC4-HMAC"
}
}
}

function Debug-ChannelEncryption
{
[CmdletBinding()]
Expand Down Expand Up @@ -3657,6 +3820,8 @@ function Debug-AzStorageAccountEntraKerbAuth {
"CheckIpHlpScv" = [CheckResult]::new("CheckIpHlpScv");
"CheckFiddlerProxy" = [CheckResult]::new("CheckFiddlerProxy");
"CheckEntraJoinType" = [CheckResult]::new("CheckEntraJoinType")
"CheckClientSupportedEncryptionTypes" = [CheckResult]::new("CheckClientSupportedEncryptionTypes");
"CheckServerSupportedEncryptionTypes" = [CheckResult]::new("CheckServerSupportedEncryptionTypes");
}
#
# Port 445 check
Expand Down Expand Up @@ -4055,6 +4220,76 @@ function Debug-AzStorageAccountEntraKerbAuth {
$checks["CheckEntraJoinType"].Issue = $_
}
}

#
# Check Client Supported Encryption Types
#

if (!$filterIsPresent -or $Filter -match "CheckClientSupportedEncryptionTypes")
{
try {
$checksExecuted += 1;
Write-Host "Checking Client Supported Encryption Types"

$clientEncryption = Get-ClientSupportedEncryptionTypes

if ($clientEncryption.SupportsAES256) {
$checks["CheckClientSupportedEncryptionTypes"].Result = "Passed"
Write-TestingPassed
}
else {
$message = "Entra Kerberos requires AES256 encryption to be enabled." `
+ " To enable AES256 encryption, open Local Group Policy Editor and edit the following policy:" `
+ " '$($PSStyle.Foreground.BrightCyan)Computer Configuration -> Windows Settings -> Security Settings -> Local Policies -> Security Options -> Network security: Configure encryption types allowed for Kerberos$($PSStyle.Reset)'" `
+ " and ensure that 'AES256_HMAC_SHA1' is checked."

$checks["CheckClientSupportedEncryptionTypes"].Result = "Failed"
$checks["CheckClientSupportedEncryptionTypes"].Issue = "AES256 encryption type is not enabled."
Write-TestingFailed -Message $message
}
} catch {
$checks["CheckClientSupportedEncryptionTypes"].Result = "Failed"
$checks["CheckClientSupportedEncryptionTypes"].Issue = $_
Write-TestingFailed -Message $_
}
}

#
# Check Server Supported Encryption Types
#

if (!$filterIsPresent -or $Filter -match "CheckServerSupportedEncryptionTypes")
{
try {
$checksExecuted += 1;
Write-Host "Checking Server Supported Encryption Types"

$serverEncryption = Get-ServerSupportedEncryptionTypes -StorageAccountName $StorageAccountName -ResourceGroupName $ResourceGroupName

if ($serverEncryption.SupportsKerberos -and $serverEncryption.SupportsAES256) {
$checks["CheckServerSupportedEncryptionTypes"].Result = "Passed"
Write-TestingPassed
}
else {
$disabledConfiguration = (-not $serverEncryption.SupportsKerberos) ? "Kerberos Authentication" : "AES-256 encryption"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Should we print both if both are required? Haven't tested the code below, but something like this:

$disabledConfiguration = @()
if (-not $serverEncryption.SupportsKerberos) { $disabledConfiguration += "Kerberos authentication" }
if (-not $serverEncryption.SupportsAES256) { $disabledConfiguration += "AES-256 encryption" }
$message = "Entra Kerberos requires $($disabledConfiguration -join ", ") to be enabled on the storage account"

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

It seems that when Kerberos is disabled (at least through the portal) it also disables all the encryption types. So I kept the same message but added a reminder to enable AES-256 when enabling Kerberos in the case Kerberos is disabled


$message = "Entra Kerberos requires $disabledConfiguration to be enabled on the storage account."
if (-not $serverEncryption.SupportsKerberos) {
$message += " When enabling Kerberos Authentication, make sure to also enable AES-256 encryption."
}

$checks["CheckServerSupportedEncryptionTypes"].Result = "Failed"
$checks["CheckServerSupportedEncryptionTypes"].Issue = "$disabledConfiguration is not enabled."
Write-TestingFailed -Message $message
}
} catch {
$checks["CheckServerSupportedEncryptionTypes"].Result = "Failed"
$checks["CheckServerSupportedEncryptionTypes"].Issue = $_
Write-TestingFailed -Message $_
}
}


SummaryOfChecks -checks $checks -filterIsPresent $filterIsPresent -checksExecuted $checksExecuted
}
}
Expand Down Expand Up @@ -4311,7 +4546,6 @@ function Debug-EntraKerbAdminConsent {
}
}


function Debug-AzStorageAccountADDSAuth {
<#
.SYNOPSIS
Expand Down