-
Notifications
You must be signed in to change notification settings - Fork 929
Add AWS4 support in the S3_RGW_OUTSCALE provider #736
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Hey @jmunhoz I remember the AWS4 auth algorithm works with GET and POST, but I'm not so sure about PUT. Can you please check that you can upload files using these changes |
@tonybaloney I would expect S3RGWOutscaleConnectionAWS4 (https://github.com/jmunhoz/libcloud/blob/s3-rgw-outscale-aws4/libcloud/storage/drivers/s3.py#L1021) having the same behaviour as S3APNE2Connection (https://github.com/jmunhoz/libcloud/blob/s3-rgw-outscale-aws4/libcloud/storage/drivers/s3.py#L987). I ran a smoke test listing objects (GET) and the testing suite. They were ok. As suggested I will check the PUT case explicitly ASAP. Thanks! |
bc6512b
to
8708b9c
Compare
@tonybaloney I reviewed the PUT case. The Libcloud code required one minor fix to handle the different behaviour related to ETags in the Amazon S3 and Ceph RGW implementations. Ceph RGW is not shipping ETag headers in this case so the code needs to handle the case where ETags don't exist. BTW, Ceph RGW was not handling the case for unsigned payloads in the PUT method so I pushed this support in Ceph and it is upstream now with Jewel 10.2.0 The PUT method is working now. Tests are passing. The header dumps for Amazon S3 and Ceph RGW using the new patch follow... Amazon S3 --------- PUT /my-container-12345678901234/my-name-12345678901234 HTTP/1.1 X-AMZ-Content-SHA256: UNSIGNED-PAYLOAD Content-Length: 12 Accept-Encoding: gzip,deflate X-AMZ-Date: 20160501T164719Z x-amz-storage-class: STANDARD Content-Type: text/plain Host: s3.eu-central-1.amazonaws.com Authorization: AWS4-HMAC-SHA256 Credential=12345678901234567890/20160502/eu-central-1/s3/aws4_request, SignedHeaders=accept-encoding;content-length;content-type;host;user-agent;x-amz-content-sha256;x-amz-date;x-amz-storage-class, Signature=3200c1e45af4ef5acde510877d1b78541337b7c90f420012d694a04a13cebcd5 User-Agent: libcloud/1.0.0-rc2 (OUTSCALE Ceph RGW S3 (eu-central-1)) Hello test! HTTP/1.1 200 OK x-amz-id-2: FiEe9rH1Rmgb7+palW18yvo6cVNt1TE90UbLwC3syxRiu0DNuDWMwzGSZMQT0ao7srkGyqOmQi4= x-amz-request-id: CC7007FFB4A71C44 Date: Sun, 01 May 2016 16:47:20 GMT ETag: "8ac91dd17dd64e95271601b773859aaa" Content-Length: 0 Server: AmazonS3 Ceph RGW --------- PUT /my-container-12345678901234/my-name-12345678901234 HTTP/1.1 X-AMZ-Content-SHA256: UNSIGNED-PAYLOAD Content-Length: 12 Accept-Encoding: gzip,deflate X-AMZ-Date: 20160501T185440Z x-amz-storage-class: STANDARD Content-Type: text/plain Host: osu.eu-west-1.outscale.com Authorization: AWS4-HMAC-SHA256 Credential=12345678901234567890/20160502/eu-west-1/s3/aws4_request, SignedHeaders=accept-encoding;content-length;content-type;host;user-agent;x-amz-content-sha256;x-amz-date;x-amz-storage-class, Signature=fb7503d5014ce581723d9695a1395bb668a3a5fcee713663de3d7a316d9b4b27 User-Agent: libcloud/1.0.0-rc2 (OUTSCALE Ceph RGW S3 (eu-west-1)) Hello test! HTTP/1.1 200 OK ETag: "8ac91dd17dd64e95271601b773859aaa" Content-Length: 0 Accept-Ranges: bytes x-amz-request-id: tx000000000000000000012-00572650f0-1017-default Date: Sun, 01 May 2016 18:54:40 GMT |
Great work. LGTM 👍 |
def _get_s3_rgw_outscale_conn_by_sign_version(signature_version): | ||
|
||
# aws4 connection support | ||
class S3RGWOutscaleConnectionAWS4(SignedAWSConnection, BaseS3Connection): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer to make those classes top-level and define them outside of this function, but that's mostly a style thing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
d01121b
to
4f3d678
Compare
@Kami I added the suggested improvements. After some tests I finished adding the dispatching code between the connection classes as part of the _ex_connection_class_kwargs method. It is working with the case you mentioned. |
4f3d678
to
ba436e9
Compare
super(S3RGWOutscaleStorageDriver, self).__init__(key, secret, | ||
secure, host, port, | ||
api_version, region, | ||
**kwargs) | ||
|
||
def _ex_connection_class_kwargs(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With this approach, the same issue exists as before - you need to do something along the lines of:
def _ex_connection_class_kwargs(self):
kwargs = {}
kwargs['signature_version'] = self.signature_version
return kwargs
And you also need to modify connection class to take signature_version
argument (or similar) and use this argument to correctly set host attribute on the connection class inside the constructor.
I'm also fine with merging this approach for now, as long as we add some test cases for it (a test case where you instantiate two drivers with different signature versions and verify that the connectionCls and connectionCls.host is set correctly) so it's easy to refactor and fix in the near future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Kami done. Added the modifications. I tested with the shared snippet and it looks okay now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jmunhoz Thanks for the update and sorry to bug you again, but this still won't work correctly.
You are still manipulating connectionCls inside the driver constructor. You should get rid of this code and as mentioned above, update connection class constructor to take signature_version
argument and correctly set host inside the connection class constructor.
This _ex_connection_class_kwargs
method doesn't actually do anything at this point, it doesn't throw because connection class declares **kwargs
. So in short, connection class constructor accepts this argument, but doesn't do anything with it.
In any case, I can go ahead, merge this into master as is and add a (failing) test case so this can be fixed in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Kami Thanks for the review. It is very appreciated.
Yes, please. Feel free to merge. We can continue improving the code over the upstream version. I guess my next patch would build on a similar bug so they could be fixed together.
I guess the example code I used at #736 (comment) is not catching the issue properly although it looks working ok? I am manipulating the connectionCls inside the driver constructor cause it looks the only place to choose between the two different connection classes without a further modification.
This patch adds AWS4 auth protocol support in the S3_RGW_OUTSCALE provider. It is needed to use AWS4 with Ceph RGW Jewel. Ceph Jewel ships with AWS2 and AWS4 enabled by default. In the case of regions and signature binding, Ceph does not enforce any signature version per region. Every region supports AWS2 and AWS4. Ceph detects the signature version per request in order to authenticate properly. More information on the Ceph's AWS4 implementation: http://docs.ceph.com/docs/master/release-notes/#v10-1-0-jewel-release-candidate http://blogs.igalia.com/jmunhoz/blog/2016/03/01/aws-signature-version-4-goes-upstream-in-ceph.html Signed-off-by: Javier M. Mellid <jmunhoz@igalia.com>
ba436e9
to
608ac11
Compare
@Kami updated! I tested the 'last connectionCls wins' issue with the following code: $ cat ex.py #!/usr/bin/env python from libcloud.storage.types import Provider, ContainerDoesNotExistError from libcloud.storage.providers import get_driver import libcloud container_name = 'container-example' object_name = 'object-example' cls = get_driver(Provider.S3_RGW_OUTSCALE) driver1 = cls('id', 'secret', region='eu-west-1', secure=False, signature_version='4') driver2 = cls('id', 'secret', region='us-east-2', secure=False, signature_version='2') print "driver1.connectionCls = %s" % (driver1.connectionCls) print "driver1.connectionCls.host = %s" %( driver1.connectionCls.host) print "driver2.connectionCls = %s" % (driver2.connectionCls) print "driver2.connectionCls.host = %s" %( driver2.connectionCls.host) $ ./ex.py driver1.connectionCls = <class 'libcloud.storage.drivers.s3.S3RGWOutscaleConnectionAWS4'> driver1.connectionCls.host = osu.eu-west-1.outscale.com driver2.connectionCls = <class 'libcloud.storage.drivers.s3.S3RGWOutscaleConnectionAWS2'> driver2.connectionCls.host = osu.us-east-2.outscale.com |
Made a small change (09638ed) and merged it into trunk - thanks! P.S. I forgot to close the PR in the commit message, can you please close this PR? |
Thanks! closing this PR |
…tent-type for data has to be json. data param of connection request must be string, changed that. Closes apache#775 Closes apache#736 Closes apache#736
This patch adds AWS4 auth protocol support in the S3_RGW_OUTSCALE
provider. It is needed to use AWS4 with the upcoming version of Ceph RGW
(Jewel)
Ceph Jewel will ship with AWS2 and AWS4 enabled by default.
In the case of regions and signature binding, Ceph does not enforce any
signature version per region. Every region supports AWS2 and AWS4. Ceph
detects the signature version per request in order to authenticate
properly.
More information on the Ceph's AWS4 implementation:
http://docs.ceph.com/docs/master/release-notes/#v10-1-0-jewel-release-candidate
http://blogs.igalia.com/jmunhoz/blog/2016/03/01/aws-signature-version-4-goes-upstream-in-ceph.html