I am trying to create a working signed PUT url to create a GCP asset in code.
I have been using this resource from the Google docs: GCP Signed URL Client Library
To try to generate GET and PUT signed URLs for GCS. I am using the Go client library code.
The GET works fine, when I use curl -I -v to validate the signed URL it comes back as 200. My PUT, however, I cannot manage to get working. Generating any URL will give a 400
I believe it might be a Content-Type issue. If I remove the content type I get a 403, but I know the client I am using to generate the signed URLs are authenticated as the GET to a private resource works.
I have also tried multiple Content-Types for testing, as in the example the Content-Type is set inside of the Headers field, whereas there is also an explicit Content-Type field:
The content I am working with is a .mov file so I have tried the below as well with video/quicktime
opts := &storage.SignedURLOptions{
...
Headers: []string{
"Content-Type:application/octet-stream",
},
...
}
opts := &storage.SignedURLOptions{
...
Content-Type: "application/octet-stream",
...
}
If anyone has any suggestions or an example of a working PUT signed URL generation that I could use as a starting point it would be really appreciated. I have looked online and it seems to be a prevalent problem with signed URLs
Here is the full code snippet:
func GenerateV4PutObjectSignedURL(bucket, object string, client storage.Client) (string, error) {
opts := &storage.SignedURLOptions{
Scheme: storage.SigningSchemeV4,
Method: "PUT",
Headers: []string{
"Content-Type:application/octet-stream",
// "Content-Type:video/quicktime",
},
Expires: time.Now().Add(15 * time.Minute),
}
u, err := client.Bucket(bucket).SignedURL(object, opts)
if err != nil {
return "", fmt.Errorf("Bucket(%q).SignedURL: %w", bucket, err)
}
return u, nil
}
And here is the output of curl -I -v <signed-url>:
* Trying 172.253.116.207:443...
* Connected to storage.googleapis.com (172.253.116.207) port 443 (#0)
* ALPN: offers h2,http/1.1
* (304) (OUT), TLS handshake, Client hello (1):
* CAfile: /etc/ssl/cert.pem
* CApath: none
* (304) (IN), TLS handshake, Server hello (2):
* (304) (IN), TLS handshake, Unknown (8):
* (304) (IN), TLS handshake, Certificate (11):
* (304) (IN), TLS handshake, CERT verify (15):
* (304) (IN), TLS handshake, Finished (20):
* (304) (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / AEAD-CHACHA20-POLY1305-SHA256
* ALPN: server accepted h2
* Server certificate:
* subject: CN=storage.googleapis.com
* start date: Jun 13 16:52:01 2024 GMT
* expire date: Sep 5 16:52:00 2024 GMT
* subjectAltName: host "storage.googleapis.com" matched cert's "storage.googleapis.com"
* issuer: C=US; O=Google Trust Services; CN=WR2
* SSL certificate verify ok.
* using HTTP/2
* h2 [:method: HEAD]
* h2 [:scheme: https]
* h2 [:authority: storage.googleapis.com]
* h2 [:path: /troves-private-test-bucket/some-new-object.png?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=troves-test-sa%40diddo-dev-387812.iam.gserviceaccount.com%2F20240710%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20240710T142122Z&X-Goog-Expires=899&X-Goog-Signature=80463c23fc383d3a56c4de30634ade843e12ea93c85768e99beb638ef87460f15ae050e4d65c694c3613dac8681daf04493198cba3104768e21cbd11dc22c193b370defbd2b14eae75e153b56a5d6c6ea2fb2fb12ac86cd67c395f8c4c09be303a9dff13dd8dbbbc25c34a3adb6fb0bde9c4d269a4a3b95d0175b6224ed330109be070ff6645e140bd1df3cdd1e4f1c597c51b12aa54740d788c1d1613178ab3285b7e077eae1830bf1eebf1e82d359fb52d2aba83bee87b63b68572d00fce562d86239451ce1038dc95b9d2c139d1e7a9434e73c691151205cdc1c1e0952e416f43e14eadd2f89b99cba14712fd2bd299ec5efba862e7d9c30dcff5c249bea5&X-Goog-SignedHeaders=content-type%3Bhost]
* h2 [user-agent: curl/8.1.2]
* h2 [accept: */*]
* Using Stream ID: 1 (easy handle 0x12f80a800)
> HEAD /troves-private-test-bucket/some-new-object.png?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=troves-test-sa%40diddo-dev-387812.iam.gserviceaccount.com%2F20240710%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20240710T142122Z&X-Goog-Expires=899&X-Goog-Signature=80463c23fc383d3a56c4de30634ade843e12ea93c85768e99beb638ef87460f15ae050e4d65c694c3613dac8681daf04493198cba3104768e21cbd11dc22c193b370defbd2b14eae75e153b56a5d6c6ea2fb2fb12ac86cd67c395f8c4c09be303a9dff13dd8dbbbc25c34a3adb6fb0bde9c4d269a4a3b95d0175b6224ed330109be070ff6645e140bd1df3cdd1e4f1c597c51b12aa54740d788c1d1613178ab3285b7e077eae1830bf1eebf1e82d359fb52d2aba83bee87b63b68572d00fce562d86239451ce1038dc95b9d2c139d1e7a9434e73c691151205cdc1c1e0952e416f43e14eadd2f89b99cba14712fd2bd299ec5efba862e7d9c30dcff5c249bea5&X-Goog-SignedHeaders=content-type%3Bhost HTTP/2
> Host: storage.googleapis.com
> User-Agent: curl/8.1.2
> Accept: */*
>
< HTTP/2 400
HTTP/2 400
< content-type: application/xml; charset=UTF-8
content-type: application/xml; charset=UTF-8
< content-length: 285
content-length: 285
< x-guploader-uploadid: ACJd0NrDypTcym06ny9UhPIuOW1-IJ_VEYiXb8CSVKe7FGpwI2PMNke_uN-F7WuVV3lemrOsoXWoYc9mAA
x-guploader-uploadid: ACJd0NrDypTcym06ny9UhPIuOW1-IJ_VEYiXb8CSVKe7FGpwI2PMNke_uN-F7WuVV3lemrOsoXWoYc9mAA
< date: Wed, 10 Jul 2024 14:21:33 GMT
date: Wed, 10 Jul 2024 14:21:33 GMT
< expires: Wed, 10 Jul 2024 14:21:33 GMT
expires: Wed, 10 Jul 2024 14:21:33 GMT
< cache-control: private, max-age=0
cache-control: private, max-age=0
< server: UploadServer
server: UploadServer
< alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
<
* Connection #0 to host storage.googleapis.com left intact
Thank you for your help