Skip to content
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

Fix object_store 0.5.0 SignatureDoesNotMatch with Minio #112

Closed
mildbyte opened this issue Sep 15, 2022 · 1 comment · Fixed by #113
Closed

Fix object_store 0.5.0 SignatureDoesNotMatch with Minio #112

mildbyte opened this issue Sep 15, 2022 · 1 comment · Fixed by #113

Comments

@mildbyte
Copy link
Contributor

 ~/seafowl/examples/multinode $ curl -i -H "Content-Type: application/json" localhost:8080/q   -d '{"query": "CREATE TABLE tripdata AS SELECT * FROM staging.tripdata"}'
HTTP/1.1 400 Bad Request
Server: nginx/1.23.1
Date: Thu, 15 Sep 2022 09:51:36 GMT
Content-Length: 803
Connection: keep-alive
vary: Content-Type, Origin, X-Seafowl-Query

Object Store error: Generic S3 error: Error performing create multipart request: response error "<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message><Key>9bf2215e727bf8d194973f5346daa1c7ce4ed17c05dd4e590ab365dc995fa997.parquet</Key><BucketName>seafowl</BucketName><Resource>/seafowl/9bf2215e727bf8d194973f5346daa1c7ce4ed17c05dd4e590ab365dc995fa997.parquet</Resource><RequestId>1714FFDF2B463C6E</RequestId><HostId>b0ac6bdc-1f16-40f2-9fe6-c2025e3e134f</H

tcpdump of Seafowl <> Minio comms:

Frame 92: 533 bytes on wire (4264 bits), 533 bytes captured (4264 bits)
Linux cooked capture
Internet Protocol Version 4, Src: 172.25.0.4, Dst: 172.25.0.2
Transmission Control Protocol, Src Port: 35334, Dst Port: 9000, Seq: 1, Ack: 1, Len: 465
Hypertext Transfer Protocol
    POST /seafowl/0c509e2d1a1b69006c40072c9ee40c525fcd8eb8443060058ab44c73ad6c54bf.parquet?uploads HTTP/1.1\r\n
    x-amz-date: 20220915T095136Z\r\n
    x-amz-content-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\r\n
    authorization: AWS4-HMAC-SHA256 Credential=minioadmin/20220915//s3/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=0aeb8d2eed42e74260c91724a349823dc659f6dfbdde0670ac91f5869ace4b2e\r\n
    accept: */*\r\n
    host: minio:9000\r\n
    \r\n
    [Full request URI: http://minio:9000/seafowl/0c509e2d1a1b69006c40072c9ee40c525fcd8eb8443060058ab44c73ad6c54bf.parquet?uploads]
    [HTTP request 1/3]
    [Response in frame: 94]
    [Next request in frame: 96]

Frame 94: 1002 bytes on wire (8016 bits), 1002 bytes captured (8016 bits)
Linux cooked capture
Internet Protocol Version 4, Src: 172.25.0.2, Dst: 172.25.0.4
Transmission Control Protocol, Src Port: 9000, Dst Port: 35334, Seq: 1, Ack: 466, Len: 934
Hypertext Transfer Protocol
    HTTP/1.1 403 Forbidden\r\n
    Accept-Ranges: bytes\r\n
    Content-Length: 529\r\n
    Content-Security-Policy: block-all-mixed-content\r\n
    Content-Type: application/xml\r\n
    Server: MinIO\r\n
    Strict-Transport-Security: max-age=31536000; includeSubDomains\r\n
    Vary: Origin\r\n
    Vary: Accept-Encoding\r\n
    X-Amz-Request-Id: 1714FFDF2AEB6157\r\n
    X-Content-Type-Options: nosniff\r\n
    X-Xss-Protection: 1; mode=block\r\n
    Date: Thu, 15 Sep 2022 09:51:36 GMT\r\n
    \r\n
    [HTTP response 1/3]
    [Time since request: 0.000320000 seconds]
    [Request in frame: 92]
    [Next request in frame: 96]
    [Next response in frame: 98]
    [Request URI: http://minio:9000/seafowl/0c509e2d1a1b69006c40072c9ee40c525fcd8eb8443060058ab44c73ad6c54bf.parquet?uploads]
    File Data: 529 bytes
eXtensible Markup Language
@mildbyte
Copy link
Contributor Author

This looks like a disparity between object_store and the official Minio SDK. object_store uses these inputs to build a signature:


string_to_sign = "AWS4-HMAC-SHA256\n20220915T105705Z\n20220915//s3/aws4_request\nb1f63c698039ba6772a850c3f0df8dc7e4f544854197ff42ff46f8f0c45e9e0d"

scope = "20220915//s3/aws4_request"

hashed_canonical_request = "b1f63c698039ba6772a850c3f0df8dc7e4f544854197ff42ff46f8f0c45e9e0d"

canonical_request = "POST\n/seafowl/bc444215ffac9df867e0b9a26184e67df061dd50a1fd2de3d3f3e335f1f85de3.parquet\nuploads\nhost:localhost:9000\nx-amz-content-sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\nx-amz-date:20220915T105705Z\n\nhost;x-amz-content-sha256;x-amz-date\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"

signed_headers = "host;x-amz-content-sha256;x-amz-date"

canonical_headers = "host:localhost:9000\nx-amz-content-sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\nx-amz-date:20220915T105705Z\n"

header_digest = http::header::value::HeaderValue {inner: bytes::bytes::Bytes {ptr: 0x7fffec05c4d0 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\031\f\375\020eϊ\027q\306\f\000", len: 64, data: core::sync::atomic::AtomicPtr<()> {p: core::cell::UnsafeCell<*mut ()> {value: 0x7fffec05c4d1}}, vtable: 0x55555bfc2fe0 <bytes::bytes::PROMOTABLE_EVEN_VTABLE>}, is_sensitive: false}

digest = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"

date_val = http::header::value::HeaderValue {inner: bytes::bytes::Bytes {ptr: 0x7fffec47d5b0 "20220915T105705Z:9000\177\000", len: 16, data: core::sync::atomic::AtomicPtr<()> {p: core::cell::UnsafeCell<*mut ()> {value: 0x7fffec47d5b1}}, vtable: 0x55555bfc2fe0 <bytes::bytes::PROMOTABLE_EVEN_VTABLE>}, is_sensitive: false}

date_str = "20220915T105705Z"

host_val = http::header::value::HeaderValue {inner: bytes::bytes::Bytes {ptr: 0x7fffec47d590 "localhost:9000\000", len: 14, data: core::sync::atomic::AtomicPtr<()> {p: core::cell::UnsafeCell<*mut ()> {value: 0x7fffec47d591}}, vtable: 0x55555bfc2fe0 <bytes::bytes::PROMOTABLE_EVEN_VTABLE>}, is_sensitive: false}

This is the main part:

canonical_request = "POST\n/seafowl/bc444215ffac9df867e0b9a26184e67df061dd50a1fd2de3d3f3e335f1f85de3.parquet\nuploads\nhost:localhost:9000\nx-amz-content-sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\nx-amz-date:20220915T105705Z\n\nhost;x-amz-content-sha256;x-amz-date\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

(note the query string is uploads)

When using the official Minio SDK to perform a multipart upload:

from io import BytesIO

import minio
from minio.helpers import MIN_PART_SIZE

client = minio.Minio("localhost:9000", "minioadmin", "minioadmin", secure=False)

data = BytesIO(b"test" * 10000000)
client.put_object(
    bucket_name="seafowl",
    object_name="test_multipart",
    data=data,
    part_size=MIN_PART_SIZE,
    length=40000000,
)

we get these inputs (note that this is a different file, I was just looking for discrepancies between what goes into the signature):

image

There are two differences here:

  • the region isn't empty (us-east-1) in minio-py whereas it is in the object_store (because we make it empty)
  • the URL to initiate a multipart upload has a ?uploads= query param in minio-py instead of ?uploads (object_store)

Setting the region to us-east in object_store doesn't fix this, but changing object_store to use ?uploads= instead of ?uploads does. I haven't looked at the Minio signature verification code itself to see if we should keep the URL the same and change the object_store signing code instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant