使用nginx代理s3服务(私有云存储)

1、背景

公司网络安全原因,私有部署s3服务的机器无法被直接访问,所以需要加一层代理,通过访问代理去访问s3服务器,这里使用nginx进行代理。使用s3服务的方式是在代码中使用官方的java s3 sdk(本文对于其他语言的官方sdk也适用)。
由于在配置过程中遇到了一些问题,如果不对s3协议的签名校验规则比较了解就难以解决此问题,故在此记录分享一下。

2、配置

官方sdk访问云存储提供了方便的接口,下载文件直接getObject(),上传文件直接putObject(),可以让我们不需要关心底层的逻辑,专注与我们的业务开发。sdk在被调用getObject()方法时,会把我们的获取文件动作封装成一个http请求发送出去,sdk封装的请求的过程中会在请求头中放入一些信息,以让s3服务端对请求进行验证。下面展示一个“获取云存储中的所有桶信息”的请求与响应的http报文(云存储地址为10.11.12.13),注意观察请求头中多了一些认证相关的信息:

请求
GET / HTTP/1.1
Host: 10.11.12.13
amz-sdk-invocation-id: *****
amz-sdk-request: attempt=1;max=4
amz-sdk-retry: 0/0/500
Authorization: AWS4-HMAC-SHA256 Credential=*****, SignedHeaders=*****, Signature=*****
Content-Type: application/octet-stream
User-Agent: aws-sdk-java/*****
x-amz-content-sha256: *****
X-Amz-Date: 20231123T015112Z
Content-Length: 0
Connection: Keep-Alive

响应
HTTP/1.1 200 OK
Content-Length: 785
Date: Thu, 23 Nov 2023 01:50:57 GMT
Vary: Origin
Connection: keep-alive

<?xml version="1.0" encoding="utf-8"?>
<ListAllMyBucketsResult xmlns="http://s3.amazonaws.com/doc/2006-03-01">
	<Owner>
		<ID>*****</ID>
		<DisplayName>*****</DisplayName>
	</Owner>
	<Buckets>
		<Bucket>
			<Name>*****</Name>
			<CreationDate>2023-09-28T08:49:10.000Z</CreationDate>
		</Bucket>
	</Buckets>
</ListAllMyBucketsResult>

重点: sdk在计算摘要时,会将请求的路径和请求Host参与摘到计算,所以一定要确保sdk访问nginx的uri和nginx访问云存储的uri保持一致(即请求头中的Host和请求路径要保持不变)。
这个怎么理解呢,直接看下面的两个报文,一个是sdk请求nginx的报文(nginx地址9.8.7.6),一个是nginx转发请求s3服务的报文,可以观察一下nginx转发后请求头中的哪些内容发生了变化,正是这些报文的变化导致了nginx转发到s3服务的请求失败(报错InvalidDigest,SignatureDoesNotMatch):

sdk请求nginx的报文
GET /xxx/x HTTP/1.1
Host: 9.8.7.6
amz-sdk-invocation-id: *****
amz-sdk-request: attempt=1;max=4
amz-sdk-retry: 0/0/500
Authorization: AWS4-HMAC-SHA256 Credential=*****, SignedHeaders=*****, Signature=*****
Content-Type: application/octet-stream
User-Agent: aws-sdk-java/*****
x-amz-content-sha256: *****
X-Amz-Date: 20231123T114100Z
Content-Length: 0
Connection: Keep-Alive

nginx转发请求s3服务的报文
GET / HTTP/1.0
Host: 10.11.12.13
Connection: close
Content-Length: 0
amz-sdk-invocation-id: *****
amz-sdk-request: attempt=1;max=4
amz-sdk-retry: 0/0/500
Authorization: AWS4-HMAC-SHA256 Credential=*****, SignedHeaders=*****, Signature=*****
Content-Type: application/octet-stream
User-Agent: aws-sdk-java/*****
x-amz-content-sha256: *****
X-Amz-Date: 20231123T114100Z

上面我们可以发现两处不同:
在这里插入图片描述
sdk请求到nginx的路径是配置nginx代理规则的时候配的,当请求路径以 /xxx/x开头时,将请求转发到云存储。但是nginx转发到s3服务就不需要这个路径了,所以发生了变化。sdk请求到nginx时host肯定时nginx的地址,nginx请求到云存储时host肯定是云存储的地址,这样没问题。
nginx的这两个在转发后的变化非常合理,但是却导致了云存储认证的时候报错。原因就是sdk在发送请求时将 9.8.7.6/xxx/x加入了摘要的计算,但是正确的云存储访问应该是10.11.12.13/,这样就导致了问题,s3服务端那边将这个host的值和路径的值取过来进行运算,发现了不匹配,于是就报错了。
那么怎样修改使得s3那边不报错呢?很简单,只需要保证Host的值不变、sdk到nginx的路径和nginx到云存储的路径不变(即uri不变),就可以了。这里需要修改nginx的代理配置,首先要求代理的匹配规则必须为’/',然后将Host的值赋值到header中,看下面的配置:

		location / {
		    proxy_pass   http://10.11.12.13:80;
			
			proxy_set_header Host 9.8.7.6;
		}

这里一定要注意,1、匹配的规则一定是 / ,不能是/x这种自定义匹配规则。2、转发后请求头的Host的值一定要和转发前请求头中的Host值相等,这里修改Host的值并不会导致请求转发不了。
在这里插入图片描述
经过如上配置后,使用sdk访问niginx就不会出错了,摘要认证就通过了。

  • 20
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值