我正在尝试通过其 REST API 创建一个 CEPH radosgw 用户。基本上相当于:
$ radosgw-admin user create --uid=test --display-name='Test user'
来自 CEPH 的文档详细介绍了通过 REST 创建用户,看起来很简单。它没有详细介绍身份验证,它只是说
admin API 的授权复制了 S3 授权机制
尝试使用此 AWS 文档签署 HTTP 请求,这似乎是执行S3 授权机制的方式。
我正在使用 pythonPOST
并尝试了该requests
模块并且也很旧urllib
,但总是回来403 Forbidden
,我怀疑这是我的Authorization
标题——更具体地说是其中的签名。
#!/usr/bin/python3.6
import requests
from urllib.parse import urlencode
from urllib.request import Request, urlopen
import base64
import hmac
from hashlib import sha1
import datetime
access_key = 'ABCDEFGHIJKL'.encode("UTF-8")
secret_key = 'abcdefghijklmnopqrst'.encode("UTF-8")
url = 'http://rgw.local:8080/admin/user'
now = datetime.datetime.now()
now_date = now.strftime("%a, %d %b %Y %H:%M:%S %z") # 'Tue, 27 Mar 2007 19:36:42 +0000'
# String to sign:
string_to_sign = 'POST\n\napplication/json\n{}\n\n/admin/user'.format(now_date).encode("UTF-8")
print("string_to_sign = {}\n".format(string_to_sign))
# Signing
signature = base64.encodestring(
hmac.new(secret_key, string_to_sign, sha1).digest()
).strip()
headers = {'content-type':'application/json'}
headers['Authorization'] = "AWS " + access_key.decode() + ":" + signature.decode()
print("Post headers:")
for k in headers.keys():
print("'{}': '{}'".format(k, headers[k]))
print("")
user_info = {
'uid': 'test-usercreate',
'display-name': 'This is a test user created via the API',
'key-type': 's3',
'generate-key': True,
}
r = requests.post(url, data=user_info, headers=headers, verify=False)
print(repr(r), r.reason)
print(r.text)
print(r.headers)
print("Return headers:")
for k in r.headers.keys():
print("'{}': '{}'".format(k, r.headers[k]))
print("")
"""
# urllib
request = Request(url=url, data=urlencode(user_info).encode(), headers=headers)
r = urlopen(request).read().decode()
print(r)
"""
输出:
string_to_sign = b'POST\n\napplication/json\nMon, 15 Nov 2021 11:36:35 \n\n/admin/user'
Post headers:
'content-type': 'application/json'
'Authorization': 'AWS ABCDEFGHIJKL:base64encodeddigest='
<Response [403]> Forbidden
{"Code":"AccessDenied","RequestId":"tx000000000000000001b7e-006191e3d3-e96d94-default","HostId":"e96d94-default-default"}
{'Content-Length': '121', 'x-amz-request-id': 'tx000000000000000001b7e-006191e3d3-e96d94-default', 'Accept-Ranges': 'bytes', 'Content-Type': 'application/json', 'Date': 'Mon, 15 Nov 2021 04:36:35 GMT'}
Return headers:
'Content-Length': '121'
'x-amz-request-id': 'tx000000000000000001b7e-006191e3d3-e96d94-default'
'Accept-Ranges': 'bytes'
'Content-Type': 'application/json'
'Date': 'Mon, 15 Nov 2021 04:36:35 GMT'
在tcpdump
rgw 方面,我看到我正在发布的这个交易:
POST /admin/user HTTP/1.1
Host: rgw.local:8080
User-Agent: python-requests/2.20.0
Accept-Encoding: gzip, deflate
Accept: */*
content-type: application/json
Authorization: AWS ABCDEFGHIJKL:base64encodeddigest=
Content-Length: 102
Connection: close
uid=test-usercreate&display-name=This+is+a+test+user+created+via+the+API&key-type=s3&generate-key=True
签名在Authorization
标题中,唉,我没有运气找到进入 radosgw 的方式。我觉得我快到了,也许我试图构建签名的方式有一个愚蠢的错误。
上面的 AWS 文档将要签名的字符串描述为:
HTTP-Verb + "\n" +
Content-MD5 + "\n" +
Content-Type + "\n" +
Date + "\n" +
CanonicalizedAmzHeaders +
CanonicalizedResource
我要离开Content-MD5
并CanonicalizedAmzHeaders
作为空字符串(换行符),并填写其余部分。
有没有人成功使用 CEPH/RGW REST API,而不使用 eg boto3
?
boto3
如果我想例如创建存储桶(这里有所有示例),那没关系,但它不会让我使用任意POST
事务,例如创建一个 radosgw 用户。