使用Ingress Nginx代理Azure Blob Storage时签名不匹配问题
问题原因分析
Azure Blob Storage的共享密钥签名是基于请求主机名、资源路径、请求时间、x-ms-*系列头等核心信息生成的,签名验证时会严格匹配这些信息。你的场景中签名不匹配的核心原因有两点:
- 主机名不匹配:应用代码用Ingress域名
my.ingress.com生成签名,但Ingress通过upstream-vhost将请求主机头替换为Blob的真实域名teststorage8297.blob.core.windows.net,导致签名计算用的主机名和Blob验证时的主机名不一致。 - 路径不匹配:Ingress通过
rewrite-target将/blobstorage(.*)重写为$1,SDK生成签名时用的是原始路径/blobstorage/...,但实际转发到Blob的路径是去掉前缀后的/...,路径信息不匹配导致签名失效。
而SAS Token能生效是因为其签名是预先基于Blob真实域名和路径生成的,Ingress仅做转发,不会修改SAS包含的验证要素,因此可以通过验证。
解决方法
方法一:修改应用代码,确保签名要素与Blob验证一致
调整SDK的请求逻辑,让签名计算使用Blob真实域名,同时请求发送到Ingress地址:
this.aborterController = new AbortController(); const storageName = getFileStorageBlobDbConfigs().storageName; const sharedKeyCredential = new AzureStorage.StorageSharedKeyCredential( storageName, getFileStorageBlobDbConfigs().key1, ); // 自定义Pipeline,拦截请求修改URL但保留签名用的主机头 const pipeline = AzureStorage.newPipeline(sharedKeyCredential); pipeline.filters.push({ async policy(next) { return async (request) => { // 保存Blob真实主机名,用于签名计算 const originalHost = request.url.host; // 将请求URL替换为Ingress地址,保留原始路径的资源部分 const ingressPath = `/blobstorage/${request.url.pathname.substring(1)}`; request.url = new URL(`https://my.ingress.com${ingressPath}`); // 强制设置Host头为Blob真实域名,确保验证时匹配 request.headers.set('Host', originalHost); return next(request); }; } }); // 用Blob真实域名初始化Client,配合自定义Pipeline转发到Ingress this.blobServiceClient = new AzureStorage.BlobServiceClient( `https://${storageName}.blob.core.windows.net`, pipeline, ); // 连接校验 try { await new AzureBlobStorage().checkConnection(); } catch (error) { Logger.error(`连接Azure Blob Storage失败!原因是: ${(error as { message: string }).message}`); }
方法二:调整Ingress配置,适配签名规则(局限性较大)
若不想修改代码,可调整Ingress配置避免路径重写和主机头冲突,但需注意会占用整个Ingress域名:
- 移除
rewrite-target、use-regex注解 - 将Ingress路径改为
/,直接映射到Blob根路径 - 保留
upstream-vhost确保Blob能识别存储账户
修改后的Ingress配置片段:
metadata: annotations: # 移除rewrite-target和use-regex cert-manager.io/cluster-issuer: letsencrypt-production nginx.ingress.kubernetes.io/backend-protocol: HTTPS nginx.ingress.kubernetes.io/proxy-body-size: "0" nginx.ingress.kubernetes.io/upstream-vhost: teststorage8297.blob.core.windows.net spec: rules: - host: my.ingress.com http: paths: - backend: service: name: proxy-to-blob-storage port: number: 443 path: / pathType: Prefix
方法三:使用Istio VirtualService优化转发(集群已部署Istio)
利用Istio的请求重写和头管理能力,更灵活地适配签名规则:
apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: blob-storage-vs namespace: default spec: hosts: - my.ingress.com gateways: - istio-ingressgateway http: - match: - uri: prefix: /blobstorage/ rewrite: uri: / route: - destination: host: teststorage8297.blob.core.windows.net port: number: 443 headers: request: set: Host: teststorage8297.blob.core.windows.net
同时修改应用代码,让SDK生成的路径为Blob根路径(即去掉/blobstorage前缀),确保签名路径和转发后的路径一致。
内容的提问来源于stack exchange,提问作者user26640084
相关产品推荐
相关产品推荐

