Small javascript application showing how to upload/download files with GCS Signed URLs and Signed Policy Documents. This article will not cover in detail what those two mechanisms are but rather demonstrate a basic application that exercises both on the browser. This is a simple client-server app that uploads files using these two mechanisms from a user’s browser. SignedURLs w/ javascript has been done many times before (see references); this article describes SignedURLs and Policy document differences and implementations.
Briefly, SignedURLs and Policy Document based operations are similar: a URL with a signature that an unauthenticated user can perform certain GCS operations. There are a couple of differences to note:
The code snippet provided here is Flask application that provides signedURLS and Policy documents to a javascript browser. Snippet also shows how to configure CORS access for SignedURLs
Note: this is just a basic sample with some awkward javascript, nothing more. The sample here allows you to generate URLs to upload+download any file in the bucket by specifying its name.
You can find the source here
PROJECT_NAME=$(gcloud config list --format="value(core.project)")
$ gcloud iam service-accounts create urlsigner --display-name="GCS URL Signer" --project=${PROJECT_NAME}
$ gcloud iam service-accounts keys create service_account.json --iam-account=urlsigner@${PROJECT_NAME}.iam.gserviceaccount.com
gsutil mb gs://$PROJECT_NAME-urlsigner
gsutil iam ch serviceAccount:urlsigner@${PROJECT_NAME}.iam.gserviceaccount.com:roles/storage.admin gs://$PROJECT_NAME-urlsigner
Add to /etc/hosts
.
127.0.0.1 gcs.somedomain.com
Set CORS policy to allow request from a test domain:
https://gcs.somedomain.com:8081
define cors.txt
:
[
{
"origin": ["https://gcs.somedomain.com:8081"],
"responseHeader": ["Content-Type", "Authorization", "Content-Length", "User-Agent", "x-goog-resumable"],
"method": ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
"maxAgeSeconds": 3600
}
]
gsutil cors set cors.txt gs://$PROJECT_NAME-urlsigner
curl -v -X OPTIONS -H "Host: storage.googleapis.com" -H "Access-Control-Request-Method: PUT" \
-H "Origin: https://gcs.somedomain.com:8081" \
"https://storage.googleapis.com/$PROJECT_NAME-urlsigner/cors.txt"
< HTTP/2 200
< access-control-allow-origin: https://gcs.somedomain.com:8081
< access-control-max-age: 3600
< access-control-allow-methods: GET,POST,PUT,DELETE,OPTIONS
< access-control-allow-headers: Content-Type,Authorization,Content-Length,User-Agent,x-goog-resumable
< vary: Origin
main.py
, setbucketName = '$PROJECT_NAME-urlsigner'
(ofcourse use the value, not literal)
virtualenv env
source env/bin/activate
pip install -r requirements.txt
python main.py
https://gcs.somedomain.com:8081/signedurl
(you may want to enable Developer Mode
in Chrome; that will show you the CORS requests too)
Select the upload
radio button.
Define a filename to generate the URL for (default: README.md
)
Click Generate Signed URL
. This will make a request to /getSignedURL
endpoint which inturn returns a signedURL for the filename specified.
Click “Choose File” to select a file to upload.
Select “Upload SignedURL”
Verify
$ gsutil ls gs://$PROJECT_NAME-urlsigner/
gs://$PROJECT_NAME-urlsigner/README.md
Select the download
radio button.
Click Generate Signed URL
. This will make a request to /getSignedURL
endpoint which inturn returns a signedURL for the filename specified.
Click the link provided on the browser. The link will download the file requested
You can also genereate upload/download urls with gsutil or any google-cloud-storage
library
gsutil signurl -m GET service_account.json gs://$PROJECT_NAME-urlsigner/README.md
gsutil signurl -m PUT service_account.json gs://$PROJECT_NAME-urlsigner/README.md
Policy Document allows for uploads only but also provides several configurations and conditions canonical SignedURLs do not: you can define a prefix/path with which a user can upload multiple files with one URL. In the example below, one URL can upload N files to the bucket and each file must have the prefix /myfolder/
and be of Content-Type: text/plain
Access https://gcs.somedomain.com:8081/policydocument
Define a filename to generate the URL for (default: README.md
)
Click Generate Policy Document Signed URL
. This will make a request to /getSignedPolicyDocument
endpoint which inturn returns a signed policy document for the filename specified. The code snippet on the server which generates this is from the google-cloud-storage
python library bucket.generate_upload_policy()
Click “Choose File” to select a file to upload.
Select “Upload SignedURL”
Verify
$ gsutil ls gs://$PROJECT_NAME-urlsigner/myfolder/
gs://$PROJECT_NAME-urlsigner/myfolder/README.md
Policy documents can also get embedded into a form as described in the links above and in the snippet below
As an HTML form, you can post the same generated signature, file and policy document. For example:
<html>
<form action="http://storage.googleapis.com/$PROJECT_NAME-urlsigner" method="post" enctype="multipart/form-data">
<input type="hidden" name="key" value="myfolder/myfile.txt">
<input type="hidden" name="bucket" value="$PROJECT_NAME-urlsigner">
<input type="hidden" name="Content-Type" value="text/plain">
<input type="hidden" name="GoogleAccessId" value="urlsigner@${PROJECT_NAME}.iam.gserviceaccount.com">
<input type="hidden" name="acl" value="bucket-owner-read">
<input type="hidden" name="policy" value="b64encodedPolicy">
<input type="hidden" name="signature" value="b64encodedSignature">
<input name="file" type="file">
<input type="submit" value="Upload">
</form>
</html>
How to SignURL on GCE|GKE|anywhere without a key (local key, that is)
Javascript with GCS SignedURLs:
This site supports webmentions. Send me a mention via this form.