Description
When using Copy-AzStorageBlob with an OAuth storage context, the cmdlet internally calls GetUserDelegationKey and generates a user delegation SAS for the source blob URL.
This is expected at a high level because Copy Blob From URL requires the source URL to be public or authorized with SAS. However, the generated user delegation SAS appears to use a start time very close to the current request time.
In a customer scenario, the source access intermittently failed with:
AuthenticationFailed
Signature not valid in the specified key time frame
The customer did not explicitly create a SAS. Their script only used an OAuth context and Copy-AzStorageBlob:
Connect-AzAccount -Identity -Environment AzureChinaCloud -Tenant "<tenant-id>"
$ctx = New-AzStorageContext -StorageAccountName "<account-name>"
Copy-AzStorageBlob `
-Context $ctx `
-SrcContainer "<src-container>" `
-SrcBlob "<blob-name>" `
-DestContainer "<dest-container>" `
-DestBlob "<blob-name>" `
-Force
We also validated this behavior with a sanitized test account using Az.Storage 8.2.0. With New-AzStorageContext -UseConnectedAccount, Copy-AzStorageBlob -Debug shows:
POST https://<account>.blob.core.<cloud-suffix>/?restype=service&comp=userdelegationkey
Response 200 OK
HEAD https://<account>.blob.core.<cloud-suffix>/<src-container>/<blob>
?skoid=<redacted>
&sktid=<redacted>
&skt=<timestamp>
&ske=<timestamp>
&sks=b
&skv=<version>
&sv=<version>
&se=<timestamp>
&sr=b
&sp=rt
&sig=<redacted>
So the source blob access is performed with an internally generated user delegation SAS even though the user script did not explicitly create a SAS.
Expected behavior:
Copy-AzStorageBlob should avoid generating a user delegation SAS whose start time is too close to the current time, or should retry when the service returns this specific boundary error:
AuthenticationFailed
Signature not valid in the specified key time frame
Potential options:
- Backdate the generated user delegation SAS start time.
- Avoid setting a SAS start time when possible.
- Retry once after a short delay for this specific error.
This would align with Azure Storage SAS best practice guidance, which warns that setting SAS start time to the current time can cause intermittent failures due to clock skew.
Issue script & Debug output
Sanitized repro script:
$DebugPreference = 'Continue'
Connect-AzAccount -Environment AzureChinaCloud
$resourceGroupName = "<resource-group>"
$storageAccountName = "<storage-account>"
$srcContainer = "src"
$dstContainer = "dst"
$blobName = "test-copy.txt"
$ctx = New-AzStorageContext `
-StorageAccountName $storageAccountName `
-UseConnectedAccount `
-Environment AzureChinaCloud
New-AzStorageContainer -Name $srcContainer -Context $ctx -ErrorAction SilentlyContinue
New-AzStorageContainer -Name $dstContainer -Context $ctx -ErrorAction SilentlyContinue
"hello" | Set-Content "$env:TEMP\$blobName"
Set-AzStorageBlobContent `
-File "$env:TEMP\$blobName" `
-Container $srcContainer `
-Blob $blobName `
-Context $ctx `
-Force
Copy-AzStorageBlob `
-Context $ctx `
-SrcContainer $srcContainer `
-SrcBlob $blobName `
-DestContainer $dstContainer `
-DestBlob $blobName `
-Force `
-Debug
Sanitized debug output excerpt:
CopyAzureStorageBlob begin processing with ParameterSet 'ContainerName'.
Use storage account '<account>' from storage context.
Request [<client-request-id>] HEAD https://<account>.blob.core.<cloud-suffix>/<src-container>/<blob-name>
Authorization: REDACTED
Response [<client-request-id>] 200 OK
Request [<client-request-id>] POST https://<account>.blob.core.<cloud-suffix>/?restype=service&comp=userdelegationkey
Authorization: REDACTED
Response [<client-request-id>] 200 OK
Request [<client-request-id>] HEAD https://<account>.blob.core.<cloud-suffix>/<src-container>/<blob-name>?skoid=<redacted>&sktid=<redacted>&skt=<timestamp>&ske=<timestamp>&sks=b&skv=<version>&sv=<version>&se=<timestamp>&sr=b&sp=rt&sig=REDACTED
Response [<client-request-id>] 200 OK
Request [<client-request-id>] PUT https://<account>.blob.core.<cloud-suffix>/<dst-container>/<blob-name>
x-ms-copy-source: REDACTED
Authorization: REDACTED
Response [<client-request-id>] 202 Accepted
x-ms-copy-status: success
The repro above demonstrates that `Copy-AzStorageBlob` internally calls `GetUserDelegationKey` and uses a generated user delegation SAS for the source blob URL when the context is OAuth-based.
The intermittent failure observed in the customer scenario was:
AuthenticationFailed
Signature not valid in the specified key time frame
The service-side details are available internally if needed, but are not included here because they contain customer/environment-specific information.
Environment data
Name Value
---- -----
PSVersion 7.6.2
PSEdition Core
OS Microsoft Windows 10.0.26200
Platform Win32NT
Module versions
Name Version
---- -------
Az.Accounts 4.0.2
Az.Storage 8.2.0
Error output
No local `Resolve-AzError` output is available for the sanitized repro because the repro completed successfully.
The customer-observed intermittent service error was:
AuthenticationFailed
Signature not valid in the specified key time frame
Description
When using
Copy-AzStorageBlobwith an OAuth storage context, the cmdlet internally callsGetUserDelegationKeyand generates a user delegation SAS for the source blob URL.This is expected at a high level because
Copy Blob From URLrequires the source URL to be public or authorized with SAS. However, the generated user delegation SAS appears to use a start time very close to the current request time.In a customer scenario, the source access intermittently failed with:
The customer did not explicitly create a SAS. Their script only used an OAuth context and
Copy-AzStorageBlob:We also validated this behavior with a sanitized test account using
Az.Storage 8.2.0. WithNew-AzStorageContext -UseConnectedAccount,Copy-AzStorageBlob -Debugshows:So the source blob access is performed with an internally generated user delegation SAS even though the user script did not explicitly create a SAS.
Expected behavior:
Copy-AzStorageBlobshould avoid generating a user delegation SAS whose start time is too close to the current time, or should retry when the service returns this specific boundary error:Potential options:
This would align with Azure Storage SAS best practice guidance, which warns that setting SAS start time to the current time can cause intermittent failures due to clock skew.
Issue script & Debug output
Environment data
Module versions
Error output