参考了官方文档,决定采用 Customer-Provided Keys(Amazon SSE-C)方式进行加密
官网地址: http://docs.ceph.com/docs/master/radosgw/encryption/
使用boto3,测试用例如下
import boto3
import os
BUCKET = 'test-bucket'
KEY = os.urandom(32)
s3 = boto3.client('s3',
endpoint_url='http://xx.xx.xx.xx',
aws_access_key_id='xxxx',
aws_secret_access_key='xxxx')
print("Uploading S3 object with SSE-C")
s3.put_object(Bucket=BUCKET,
Key='encrypt-key',
Body=b'foobar',
SSECustomerKey=KEY,
SSECustomerAlgorithm='AES256')
print "Done"
print("Getting S3 object...")
response = s3.get_object(Bucket=BUCKET,
Key='encrypt-key',
SSECustomerKey=KEY,
SSECustomerAlgorithm='AES256')
print("Done, response body:")
print(response['Body'].read())
发现报错提示如下
botocore.exceptions.ClientError: An error occurred (InvalidRequest) when calling the PutObject operation: Unknown
InvalidRequest 也就是说提交的参数不对,于是抓包对比,截图如下
Response 的内容如下
<?xml version="1.0" encoding="UTF-8"?><Error><Code>InvalidRequest</Code><BucketName>test-bucket</BucketName><RequestId>tx00000000000000000000c-005b3ae2a0-62db-default</RequestId><HostId>62db-default-default</HostId></Error>
同时参考官网的文档https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html,发现请求Request Header内容已经符合了AWS Using SSE-C的标准,所以很费解!
由于使用的是12.2.4做测试,有朋友用12.2.5同样的测试用例通过,怀疑可能是RGW的bug,于是就着手升级测试环境到12.2.5,但是升级完成以后仍然无法报400错误。
考虑到朋友那边可能boto3的版本和我不一样,于是又调整了boto3的版本,最终还是400报错。
于是在朋友建议下打开debug_rgw=20,发现日志有异常
...
2018-07-03 10:51:09.975043 7efc1642a700 2 req 2:0.001484:s3:PUT /test-bucket/encrypt-key:put_obj:recalculating target
2018-07-03 10:51:09.975047 7efc1642a700 2 req 2:0.001488:s3:PUT /test-bucket/encrypt-key:put_obj:reading permissions
2018-07-03 10:51:09.975049 7efc1642a700 2 req 2:0.001490:s3:PUT /test-bucket/encrypt-key:put_obj:init op
2018-07-03 10:51:09.975050 7efc1642a700 2 req 2:0.001492:s3:PUT /test-bucket/encrypt-key:put_obj:verifying op mask
2018-07-03 10:51:09.975052 7efc1642a700 20 required_mask= 2 user.op_mask=7
2018-07-03 10:51:09.975053 7efc1642a700 2 req 2:0.001495:s3:PUT /test-bucket/encrypt-key:put_obj:verifying op permissions
2018-07-03 10:51:09.975056 7efc1642a700 20 -- Getting permissions begin with perm_mask=50
2018-07-03 10:51:09.975057 7efc1642a700 5 Searching permissions for identity=rgw::auth::SysReqApplier -> rgw::auth::LocalApplier(acct_user=s3test, acct_name=s3test, subuser=, perm_mask=15, is_admin=0) mask=50
2018-07-03 10:51:09.975063 7efc1642a700 5 Searching permissions for uid=s3test
2018-07-03 10:51:09.975063 7efc1642a700 5 Found permission: 15
2018-07-03 10:51:09.975064 7efc1642a700 5 Searching permissions for group=1 mask=50
2018-07-03 10:51:09.975065 7efc1642a700 5 Permissions for group not found
2018-07-03 10:51:09.975066 7efc1642a700 5 Searching permissions for group=2 mask=50
2018-07-03 10:51:09.975066 7efc1642a700 5 Permissions for group not found
2018-07-03 10:51:09.975069 7efc1642a700 5 -- Getting permissions done for identity=rgw::auth::SysReqApplier -> rgw::auth::LocalApplier(acct_user=s3test, acct_name=s3test, subuser=, perm_mask=15, is_admin=0), owner=s3test, perm=2
2018-07-03 10:51:09.975071 7efc1642a700 10 identity=rgw::auth::SysReqApplier -> rgw::auth::LocalApplier(acct_user=s3test, acct_name=s3test, subuser=, perm_mask=15, is_admin=0) requested perm (type)=2, policy perm=2, user_perm_mask=2, acl perm=2
2018-07-03 10:51:09.975074 7efc1642a700 2 req 2:0.001514:s3:PUT /test-bucket/encrypt-key:put_obj:verifying op params
2018-07-03 10:51:09.975076 7efc1642a700 2 req 2:0.001518:s3:PUT /test-bucket/encrypt-key:put_obj:pre-executing
2018-07-03 10:51:09.975093 7efc1642a700 2 req 2:0.001534:s3:PUT /test-bucket/encrypt-key:put_obj:executing
2018-07-03 10:51:09.975112 7efc1642a700 15 supplied_md5_b64=bIEkMCj45FX6YX3V8CMs4Q==
2018-07-03 10:51:09.975117 7efc1642a700 15 ceph_armor ret=16
2018-07-03 10:51:09.975122 7efc1642a700 15 supplied_md5=6c81243028f8e455fa617dd5f0232ce1
2018-07-03 10:51:09.975176 7efc1642a700 5 ERROR: Insecure request, rgw_crypt_require_ssl is set
2018-07-03 10:51:09.975197 7efc1642a700 2 req 2:0.001638:s3:PUT /test-bucket/encrypt-key:put_obj:completing
2018-07-03 10:51:09.975247 7efc1642a700 2 req 2:0.001688:s3:PUT /test-bucket/encrypt-key:put_obj:op status=-2021
2018-07-03 10:51:09.975252 7efc1642a700 2 req 2:0.001693:s3:PUT /test-bucket/encrypt-key:put_obj:http status=400
2018-07-03 10:51:09.975275 7efc1642a700 1 ====== req done req=0x7efc16424110 op status=-2021 http_status=400 ======
2018-07-03 10:51:09.975286 7efc1642a700 20 process_request() returned -2021
2018-07-03 10:51:10.045566 7efc1642a700 1 civetweb: 0x7efc49de4000: 10.13.70.5 - - [03/Jul/2018:10:51:09 +0800] "PUT /test-bucket/encrypt-key HTTP/1.1" 400 0 - Boto3/1.7.24 Python/2.7.10 Darwin/17.6.0 Botocore/1.10.24
其中的ERROR: Insecure request, rgw_crypt_require_ssl is set 引起我的注意,于是检查线上配置
[root@demo]#ceph daemon /var/run/ceph/ceph-client.rgw.demo.asok config show|grep ssl
"kinetic_use_ssl": "false",
"rgw_crypt_require_ssl": "true",
"rgw_keystone_verify_ssl": "true",
"rgw_verify_ssl": "true",
发现rgw_crypt_require_ssl为true,于是改到false重启,终于成功。
rgw_crypt_require_ssl=true 是RGW的默认配置,默认配置下只有开启HTTPS才能使用Server-side Encryption,这也是为了安全起见,但是如果在HTTP下面使用Server-side Encryption,则会出现本文中的400错误,而按照400错误给出的提示,错误的原因应该在客户端提交的参数不对,这样就极大的误导了我们,所以才有了上面一轮又一轮的故事。而且最坑爹的是,朋友使用的是vstart脚本启动的测试,vstart环境默认在ceph.conf里面就加上了rgw_crypt_require_ssl=false,看样子社区开发者是知道这个问题,才在测试环境下关闭这个特性,在没有文档说明和仅靠400报错提示的情况下,很多人都容易发生像我这样的爬坑故事。