Azure / Azure/azure-powershell
Copy-AzStorageBlob with OAuth context may generate source user delegation SAS that is not yet valid
- Dominant language
- C#
- Stars
- 4.8k
- Forks
- 4.3k
- Avg merge
- 3d 14h
- Merged PRs (30d)
- 54
Description
### 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:
```text
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`:
```powershell
Connect-AzAccount -Identity -Environment AzureChinaCloud -Tenant ""
$ctx = New-AzStorageContext -StorageAccountName ""
Copy-AzStorageBlob `
-Context $ctx `
-SrcContainer "" `
-SrcBlob "" `
-DestContainer "" `
-DestBlob "" `
-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:
```text
POST https://.blob.core./?restype=service&comp=userdelegationkey
Response 200 OK
HEAD https://.blob.core.//
?skoid=
&sktid=
&skt=
&ske=
&sks=b
&skv=
&sv=
&se=
&sr=b
&sp=rt
&sig=
```
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:
```text
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
```PowerShell
Sanitized repro script:
$DebugPreference = 'Continue'
Connect-AzAccount -Environment AzureChinaCloud
$resourceGroupName = ""
$storageAccountName = ""
$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 '' from storage context.
Request [] HEAD https://.blob.core.//
Authorization: REDACTED
Response [] 200 OK
Request [] POST https://.blob.core./?restype=service&comp=userdelegationkey
Authorization: REDACTED
Response [] 200 OK
Request [] HEAD https://.blob.core.//?skoid=&sktid=&skt=&ske=&sks=b&skv=&sv=&se=&sr=b&sp=rt&sig=REDACTED
Response [] 200 OK
Request [] PUT https://.blob.core.//
x-ms-copy-source: REDACTED
Authorization: REDACTED
Response [] 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
```PowerShell
Name Value
---- -----
PSVersion 7.6.2
PSEdition Core
OS Microsoft Windows 10.0.26200
Platform Win32NT
```
### Module versions
```PowerShell
Name Version
---- -------
Az.Accounts 4.0.2
Az.Storage 8.2.0
```
### Error output
```PowerShell
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
```
Contributor guide
Research direction
Start with the Copy-AzStorageBlob OAuth path and its internal GetUserDelegationKey call, using the sanitized repro and -Debug output to trace the generated SAS timing. Done means the source URL remains usable despite clock skew, through safely timed SAS handling or the specified boundary-error handling, while the repro still copies successfully.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- azure, powershell
- Domain
- cloud
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100