使用UserDelegatedCredential和azure-sdk-for-go生成跨租户Azure Blob Storage SAS时签名不匹配
跨租户及单租户Azure Blob存储预签名URL生成403错误问题
环境与已完成配置
- 租户A拥有资源:K8s集群、托管标识、存储账户及容器
- 租户B拥有资源:托管标识、存储账户及容器
- 跨租户访问配置步骤:
- 在租户B中为其托管标识分配
Storage Account Contributor和Storage Blob Data Owner角色 - 执行以下命令创建联合凭证:
- 在租户B中为其托管标识分配
az identity federated-credential create \ --name fc-x-tenant-test \ --identity-name tenantB-managedIdentity \ --resource-group tenantB-rg \ --issuer <Tenant A AKS Cluster OIDC Provider URL> \ --subject system:serviceaccount:default:<Tenant A Service Account name>
正常工作的客户端代码
使用azure-sdk-for-go创建的客户端可成功读写租户B的存储容器,代码如下:
url := fmt.Sprintf("https://%s.blob.core.windows.net", accountName) opts := &azidentity.WorkloadIdentityCredentialOptions{ TenantID: *tenantBID, ClientID: *tenantBmanagedIdentityClientID, } cred, err := azidentity.NewWorkloadIdentityCredential(opts) client, err := azblob.NewClient(url, cred, nil) serviceClient := client.ServiceClient() containerClient := serviceClient.NewContainerClient(containerName)
问题现象
客户端读写操作正常,但生成用于PUT对象的预签名URL时返回403错误:
ErrorCode:AuthenticationFailed authenticationerrordetail:Signature did not match
预签名URL生成代码
serviceClient := client.ServiceClient() now := time.Now().UTC().Add(-10 * time.Second) expiry := now.Add(24 * time.Hour) info := azblobService.KeyInfo{ Start: to.Ptr(now.UTC().Format(sas.TimeFormat)), Expiry: to.Ptr(expiry.UTC().Format(sas.TimeFormat)), } udc, err := serviceClient.GetUserDelegationCredential(ctx, info, nil) sigVals := sas.BlobSignatureValues{ Protocol: sas.ProtocolHTTPS, ExpiryTime: time.Now().Add(24 * time.Hour).UTC(), Permissions: perm.String(), ContainerName: containerName, BlobName: blobName, } query, err := sigVals.SignWithUserDelegation(udc)
排查信息
- 日志中
ExpiryTime格式看似异常,但单租户使用共享访问密钥时该格式可正常工作 - 调整
signedStart参数后问题仍未解决 - 租户B存储账户日志可记录非SAS的跨租户读写操作,但未捕获到失败的SAS PUT请求日志
- 更新:该问题在单租户环境中同样可复现
内容的提问来源于stack exchange,提问作者drewkumbe
相关产品推荐
相关产品推荐

