Google Cloud Storage

Access Control

There are two ways to control access to Google Cloud Storage objects and buckets:

These are not mutually exclusive. You can use ACLs to protect buckets and objects, while at the same time providing signed URLs to users so they can access those resources, bypassing the ACL mechanism.

Contents

About Access Control Lists

Google Cloud Storage uses access control lists (ACLs) to manage object and bucket access. ACLs are the mechanism you use to share objects with other users and allow other users to access your buckets and objects.

An ACL consists of one or more entries, where each entry grants permissions to a scope. Permissions define the actions that can be performed against an object or bucket (for example, READ or WRITE); the scope defines who the permission applies to (for example, a specific user or group of users). Scopes are sometimes referred to as grantees. The maximum number of ACL entries you can create for an object or bucket is 100. When the ACL scope is a group or domain, it counts as one ACL entry regardless of how many users are in the group or domain.

When a user requests access to an object or bucket, the Google Cloud Storage system reads the ACL on the object or bucket and determines whether to allow or reject the access request. If the ACL grants the user permission for the requested operation, the request is allowed. If the ACL does not grant the user permission for the requested operation, the request fails and a 403 Forbidden error (Access Denied) is returned.

Scopes and Permissions

You can specify a scope by using any of the following entities:

  • Google Storage ID

    A Google Storage ID is a string of 64 hexadecimal digits that identifies a specific Google account holder or a specific Google group. It is sometimes referred to as a canonical ID. The following is an example of a Google Storage ID:

    84fac329bceSAMPLE777d5d22b8SAMPLE77d85ac2SAMPLE2dfcf7c4adf34da46

    Project teams are identified by a Google Storage ID. The project editors group and project owners group are also identified using Google Storage IDs. These IDs are specific to each project and can be found in the Google Developers Console.

  • Google account email address

    Every user who has a Google account must have a unique email address associated with that account. You can specify a scope by using any email address that is associated with a Google account, such as a gmail.com address.

    Google Cloud Storage remembers email addresses as they are provided in ACLs until these ACLs are removed or overwritten. If a user changes email addresses, you should update ACLs to reflect these changes.

  • Google group email address

    Every Google group has a unique email address that is associated with the group. For example, the Google Cloud Storage group has the following email address: gs-discussion@googlegroups.com. You can find the email address that is associated with a Google group by clicking About this group, which appears on the homepage of every Google group. For more information about Google groups, see the Google groups homepage.

    Like with Google account email addresses, Google Cloud Storage remembers group email addresses as they are provided in ACLs until these ACLs are removed or overwritten. You do not need to worry about updating Google Group email addresses because Google Group email addresses are permanent and unlikely to change.

  • Google Apps domain

    Google Apps customers can associate their email accounts with an Internet domain name. When you do this, each email account takes the form username@yourdomain.com. You can specify a scope by using any Internet domain name that is associated with a Google Apps account.

  • Special identifier for all Google account holders

    This special scope identifier represents anyone who is authenticated with a Google account. The special scope identifier for all Google account holders is AllAuthenticatedUsers.

  • Special identifier for all users

    This special scope identifier represents anyone who is on the Internet, with or without a Google account. The special scope identifier for all users is AllUsers.

Usually, you specify scopes using an email address, a domain, or one of the special identifiers. If you want to specify a scope using a Google Storage ID, you have to determine what the Google Storage ID is. You can determine a user's Google Storage ID by retrieving the ACLs on an object that the user uploaded. You can find the user's Google Storage ID by looking in the XML document that's returned in the response body. The user's Google Storage ID appears in the <ID> element that is in the <OWNER> container.

You can also retrieve Google Storage IDs for a project team, project editors, and project owners by either retrieving ACLs on a bucket if the ACLs have not been changed from the default or by using the Google Developers Console. For more information, see Google Storage IDs for Projects.

Google Cloud Storage lets you assign the following concentric permissions for your buckets and objects:

READ WRITE FULL_CONTROL Default
Objects Lets a user download an object. You cannot apply this permission to objects. Gives a user READ access. It also lets a user read and write object ACLs and other metadata. Objects have the predefined project-private ACL applied when they are uploaded. Objects are always owned by the original requestor who uploaded the object.
Buckets Lets a user list a bucket's contents. Lets a user list, create, overwrite, and delete objects in a bucket. Gives a user READ and WRITE permissions on the bucket. It also lets a user read and write bucket ACLs and other metadata. Buckets have the predefined project-private ACL applied when they are created. Buckets are always owned by the project-owners group.

Note: You cannot grant discrete permissions for reading or writing ACLs or other metadata. To let someone read and write ACLs you must grant them FULL_CONTROL permission.

Google Storage IDs for Projects

Project teams, project editors, and project owners are identified using Google Storage IDs.

To find the Google Storage IDs for the project groups:

  1. Go to the Google Developers Console.
  2. Select a project by clicking its name.
  3. Click Cloud Storage, and then click Projet dashboard.
  4. The IDs are in the Google Cloud Storage IDs section.

Back to top

Understanding Default Bucket and Object ACLs

This section describes how default ACLs are applied to buckets and objects.

Default Bucket ACLs

All buckets are owned by the project owners group. Project owners are granted FULL_CONTROL automatically to all buckets inside their project. When you create a project, you are automatically added as a project owner.

If you create a bucket with the default bucket ACLs—that is, you do not specify a predefined ACL when you create the bucket—your bucket has the predefined project-private ACL applied to it. The project-private ACL gives additional permissions to project team members based on their roles. These additional permissions are defined as follows:

  • All Project Team Members

    The project-private ACL provides all team members with READ access to buckets in a project. All project team members can list objects within buckets. All project team members can also list buckets within a project, independent of bucket ACLs.

  • Project Editors

    The project-private ACL provides project editors with FULL_CONTROL permissions to buckets in a project. Project editors can list a bucket's contents, and create, overwrite, or delete objects in a bucket. Project editors can also list, create, and delete buckets, independent of bucket ACLs.

  • Project Owners

    The project-private ACL provides project owners with FULL_CONTROL permissions. Project owners can also perform all tasks that project editors can perform, in addition to administrative tasks like adding and removing team members, and changing billing information.

For information about project-level permission, see the project members and permissions section. For more information about project roles, see Google Developers Console Help.

Project teams, project editors, and project owners are identified using Google Storage IDs. You can find these Google Storage IDs in the Google APIs Console. This can be useful if you want to use these IDs to customize access to objects and buckets. For more information, see Google Storage IDs for Projects.

Default Object ACLs

By default, anyone who has FULL_CONTROL permission or WRITE permission on a bucket can upload objects into that bucket. When you upload an object, you can provide a predefined ACL or not specify an ACL at all. If you don't specify an ACL, Google Cloud Storage applies the bucket's default object ACL to the object. Every bucket has a default object ACL and this ACL is applied to all objects uploaded to that bucket without a predefined ACL. The initial value for the default object ACL of every bucket is project-private. You can change the default object ACL of a bucket, as described later in this document.

Based on how objects are uploaded, object ACLs are applied accordingly:

  • Authenticated Uploads

    If you make an authenticated request to upload an object and you do not specify any object ACLs when you upload it, you are listed as the owner of the object and the predefined project-private ACL is applied to the object by default. This means:

    • You (the person who uploaded the object) are listed as the object owner. Object ownership cannot be changed by modifying ACLs. You can change object ownership only by overwriting an object.
    • You (the object owner) are granted FULL_CONTROL permission on the object. If you attempt to give less than FULL_CONTROL permission to the owner, Google Cloud Storage automatically escalates the permission to FULL_CONTROL.
    • The project owners and project writers group have FULL_CONTROL permission on the object.
    • The project viewers group has READ permission on the object.

  • Anonymous Uploads

    If an unauthenticated (anonymous) user uploads an object, which is possible if a bucket grants the AllUsers group WRITE or FULL_CONTROL permission, then the default bucket ACLs are applied to the object as described above.

    Anonymous users cannot specify predefined ACLs during object upload.

    An unauthenticated (anonymous) user has the following Google Storage ID: 00b4903a97d9812a16c37f78443e7c994fa3b7e3c8d5cdc1e0f2c75c6f65318d.

Changing default object ACLs

You can change the default object ACL for a particular bucket by using the ?defaultObjectAcl query parameter. For example, you may want to specify that only a certain group of users have access to all objects in a particular bucket but do not want to manually set these ACLs on every new object. In these instances, you can change the default object ACL for the bucket that holds these objects. All new objects will have the new default object ACL applied to them.

To obtain the authorization token used in the next examples, see OAuth 2.0 Playground.

For example, using curl, you can set the default object ACL of a bucket named travel-maps to allow FULL_CONTROL access to a group called travel-companions, like so:

curl -X PUT --data-binary @acls.txt -H "x-goog-api-version: 2" -H "Authorization: OAuth 1/zVNpoQNsOSxZKqOZgckhpQ" "http://storage.googleapis.com/travel-maps?defaultObjectAcl"

The contents of acls.txt are shown below:

<AccessControlList>
  <Entries>
  <Entry>
    <Permission>FULL_CONTROL</Permission>
    <Scope type="GroupByEmail">
      <EmailAddress>travel-companions@googlegroups.com</EmailAddress>
    </Scope>
  </Entry>
  </Entries>
</AccessControlList>

You can also specify a predefined ACL as the default object ACL as well. The following example sets the default object ACL of the travel-maps bucket to public-read:

curl -X PUT -H "Content-Length: 0" -H "x-goog-api-version: 2" -H "Authorization: OAuth 1/zVNpoQNsOSxZKqOZgckhpQ" -H "x-goog-acl: public-read" "http://storage.googleapis.com/travel-maps?defaultObjectAcl"

You can also use gsutil to modify the default object ACL. See the defacl command for details.

Some things to note if you change default object ACLs:

  • Only Google ACL XML is accepted
  • Owners elements are ignored

    If you include an Owner element in your XML, Google Cloud Storage omits it. Since an object is always owned by the user who uploaded it, it is not possible to set the Owner element in advance. Google Cloud Storage supplies the Owner element and grants FULL CONTROL access to the actual owner when the object is uploaded. This also applies to predefined ACLs.

To check if a bucket has a modified default object ACL, you can perform a GET request to a bucket's defaultObjectACL query parameter:

curl -H "x-goog-api-version: 2" -H "Authorization: OAuth 1/zVNpoQNsOSxZKqOZgckhpQ" "http://storage.googleapis.com/travel-maps?defaultObjectAcl"

Google Cloud Storage returns the corresponding XML for the default object ACL. The project-private ACL would look similar to the following example:

<?xml version="1.0" ?>
<AccessControlList>
    <Entries>
         <Entry>
            <Scope type="GroupById">
                <ID>SAMPLE7808fbaSAMPLE98abSAMPLE3414de97SAMPLE8f6eSAMPLE5b45SAMPLE2</ID>
            </Scope>
            <Permission>FULL_CONTROL</Permission>
        </Entry>
         <Entry>
            <Scope type="GroupById">
                <ID>SAMPLE235855baSAMPLE98abSAMPLE3345de97SAMPLE8f6eSAMPLE5b45SAMPLE3</ID>
            </Scope>
            <Permission>FULL_CONTROL</Permission>
        </Entry>
         <Entry>
            <Scope type="GroupById">
                <ID>SAMPLE7ASDADaSAMPLE7676SAMPLE34sdad75SAMPLE8f6eSAMPLE5b45SAMPLE5</ID>
            </Scope>
            <Permission>READ</Permission>
        </Entry>
    </Entries>
</AccessControlList>

Back to top

Specifying Bucket and Object ACLs

There are three ways to specify ACLs to buckets and objects, using:

Using the acl query string parameter

You can use the acl query string parameter in conjunction with the PUT method to apply ACLs to the following: an existing object, an existing bucket, or a bucket you are creating. When you use the acl query string parameter in a PUT request, you must attach an XML document to the body of your request. The XML document contains the individual ACL entries that you want to apply to the bucket or object.

The following syntax diagram describes the syntax of a serialized ACL:

The RELAX NG Compact Syntax Format Schema describes the exact formatting requirements of the Google ACL XML.

For example, the following curl command applies an XML payload from the document acls.txt to an object named paris.jpg:

curl -X PUT --data-binary @acls.txt -H "x-goog-api-version: 2" -H "Authorization: OAuth 1/zVNpoQNsOSxZKqOZgckhpQ" "http://storage.googleapis.com/travel-maps/paris.jpg?acl"

The details of the request are shown below. This is a typical PUT request using the acl query string parameter and the corresponding XML document (in this case, acls.txt). The PUT request changes the ACLs on an object named paris.jpg that is in a bucket named travel-maps. The ACL grants jane@gmail.com FULL_CONTROL permission and it grants the members of the Google Cloud Storage group READ permission on the object paris.jpg.

PUT /paris.jpg?acl HTTP/1.1
Host: travel-maps.storage.googleapis.com
Date: Sat, 20 Feb 2010 08:31:08 GMT
Content-Length: 589
Content-Type=application/xml
x-goog-api-version: 2
Authorization: OAuth 1/zVNpoQNsOSxZKqOZgckhpQ

<?xml version='1.0' encoding='utf-8'?>
<AccessControlList>
  <Owner>
    <ID>84fac329bceSAMPLE777d5d22b8SAMPLE77d85ac2SAMPLE2dfcf7c4adf34da46</ID>
  </Owner>
  <Entries>
  <Entry>
    <Permission>FULL_CONTROL</Permission>
    <Scope type="UserById">
      <ID>84fac329bceSAMPLE777d5d22b8SAMPLE77d85ac2SAMPLE2dfcf7c4adf34da46</ID>
    </Scope>
  </Entry>
  <Entry>
    <Scope type="UserByEmail">
      <EmailAddress>jane@gmail.com</EmailAddress>
      <Name>Jane</Name>
    </Scope>
    <Permission>FULL_CONTROL</Permission>
  </Entry>
  <Entry>
    <Scope type="GroupByEmail">
      <EmailAddress>gs-discussion@googlegroups.com</EmailAddress>
    </Scope>
    <Permission>READ</Permission>
  </Entry>
  </Entries>
</AccessControlList>

You can also retrieve bucket and object ACLs by using the acl query string parameter with the GET method. The ACLs are described in an XML document, which is attached to the body of the response. You must have FULL_CONTROL permission to apply or retrieve ACLs on an object or bucket.

You can also get, set, or change the ACL of a bucket or object using the gsutil acl command.

Concentric Permissions

You can have many entries in the XML document for your ACLs, but keep in mind that it is not possible to have entries with duplicate scopes. For example, it is not possible to have two entries both with the same scope element of jane@example.com. Note that you do not need to list multiple scopes to grant multiple permissions. Google Cloud Storage uses concentric permissions so when you grant WRITE permission, you also grant READ permission, and if you grant FULL_CONTROL permission, you also grant READ and WRITE permission.

For example, it is not possible to provide two entries for Jane, one with READ permission and one with WRITE permission. Instead, you can grant Jane WRITE permission which also grants her READ permission.

Using the <Name> element in ACLs

When you retrieve an ACL from an object or bucket, you might notice an additional <Name> element appended to some of your entries. For example, you might see an entry that looks like the following:

 <Entry>
    <Scope type="UserByEmail">
      <EmailAddress>jane@gmail.com</EmailAddress>
      <Name>Jane</Name>
    </Scope>
    <Permission>FULL_CONTROL</Permission>
 </Entry>

These optional <Name> elements are populated in one of two ways:

  1. It was provided with the object or bucket's ACLs

    When you set ACLs, you may choose to include the <Name> element with your ACL entries. You can provide any value in the <Name> element and Google Cloud Storage remembers these values until the ACL is removed or overwritten. This can be useful if you are using identifiers that aren't easily identifiable, like Google Storage IDs.

  2. A UserByEmail or GroupByEmail scope was used with a public Google profile

    If you used either of these scopes but did not provide a <Name> element, Google Cloud Storage checks if the user or Google Group of the email address has a public Google profile with a public name. If so, Google Cloud Storage populates the <Name> element automatically with the public name.

The following example shows an ACL entry that uses a Google Storage ID along with the <Name> to help identify the user:

 <Entry>
    <Scope type="UserByID">
      <ID>84fac329bceSAMPLE777d5d22b8SAMPLE77d85ac2SAMPLE2dfcf7c4adf34da46</ID>
      <Name>Jane</Name>
    </Scope>
    <Permission>FULL_CONTROL</Permission>
 </Entry>

Applying ACLs with the extension request header

You can use the x-goog-acl request header to apply predefined ACLs to buckets and objects.

The following table shows which ACL entries are applied for each of the predefined ACLs. As a reference, bucket owner is the project owners group, and object owner is the user that created the object. If an object was created by an anonymous user, then the object owner is the project owners group.

Predefined ACL Description
project-private Gives permission to the project team based on their roles. Anyone who is part of the team has READ permission and project owners and project editors have FULL_CONTROL permission. This is the default ACL for newly created buckets. This is also the default ACL for newly created objects unless the default object ACL for that bucket has been changed.
private Gives the bucket or object owner FULL_CONTROL permission for a bucket or object.
public-read Gives the bucket or object owner FULL_CONTROL permission and gives all anonymous users READ permission. When you apply this to an object, anyone on the Internet can read the object without authenticating. When you apply this to a bucket, anyone on the Internet can list objects without authenticating. Important: By default, publicly readable objects are served with a Cache-Control header allowing such objects to be cached for 3600 seconds. If you need to ensure that updates become visible immediately, you should set a Cache-Control header of "Cache-Control:private, max-age=0, no-transform" on such objects. For help doing this, see the gsutil setmeta command.
public-read-write Gives the bucket owner FULL_CONTROL permission and gives all anonymous users READ and WRITE permission. This ACL applies only to buckets. When you apply this to a bucket, anyone on the Internet can list, create, overwrite and delete objects without authenticating.
authenticated-read Gives the bucket or object owner FULL_CONTROL permission and gives all authenticated Google account holders READ permission.
bucket-owner-read Gives the object owner FULL_CONTROL permission and gives the bucket owner READ permission. This is used only with objects.
bucket-owner-full-control Gives the bucket owner FULL_CONTROL permission. This is used only with objects.

You typically use the x-goog-acl header to apply a predefined ACL to a bucket or object when you are creating or uploading the bucket or object. In this case, you use the x-goog-acl header just like you would any other request header.

For example, the following curl command uploads an object paris.jpg to a bucket named travel-maps and applies the predefined ACL bucket-owner-read:

curl -X PUT --upload-file paris.jpg -H "x-goog-api-version: 2" -H "Authorization: OAuth 1/zVNpoQNsOSxZKqOZgckhpQ" -H "x-goog-acl: bucket-owner-read" "http://storage.googleapis.com/travel-maps"

The details of the request are shown below:

PUT /paris.jpg HTTP/1.1
Host: travel-maps.storage.googleapis.com
Date: Mon, 15 Feb  2008 21:30:39 GMT
Content-Length: 12345
Content-Type: image/jpg
x-goog-api-version: 2
x-goog-acl: bucket-owner-read
Authorization: OAuth 1/zVNpoQNsOSxZKqOZgckhpQ

<12345 bytes in entity body>

You can also use the x-goog-acl header to apply a predefined ACL to an existing bucket or object. To do this you include the acl query string parameter in your request but you do not include an XML document in your request. Applying a predefined ACL to an existing object or bucket is useful if you want to change from one predefined ACL to another or you want to update custom ACLs to a predefined ACL.

Note: By applying a predefined ACL to an existing bucket or object, you will completely replace the existing bucket/object ACL with the predefined ACL. This may cause the requester to lose access to the bucket or object ACL in some cases. For example, if the requester is in the project owners group but not the owner of an object with project-private ACL, then after he applies the public-read ACL to the object, he will lose the FULL_CONTROL permission and thus can no longer access the object ACL.

For example, the following curl command applies the predefined private acl to an object named paris.jpg in a bucket named travel-maps:

curl -X PUT -H "Content-Length: 0" -H "x-goog-api-version: 2" -H "Authorization: OAuth 1/zVNpoQNsOSxZKqOZgckhpQ" -H "x-goog-acl: private" "http://storage.googleapis.com/travel-maps/paris.jpg?acl"

The details of the request are shown below:

PUT /paris.jpg?acl HTTP/1.1
Host: travel-maps.storage.googleapis.com
Date: Mon, 15 Feb  2008 21:30:39 GMT
Content-Length: 0
x-goog-api-version: 2
x-goog-acl: private
Authorization: OAuth 1/zVNpoQNsOSxZKqOZgckhpQ

<empty entity body>

Managing Access Control

ACLs, like any other administrative settings, require active management to be effective. Before you make a bucket or object accessible to other users, be sure you know who you want to share the bucket or object with and be sure you know what roles you want each of those people to play. Over time, changes in project management, usage patterns, and organizational ownership may require you to modify ACL settings on buckets and objects, especially if you manage buckets and objects in a large organization or for a large group of users. As you evaluate and plan your access control settings keep the following best practices in mind:

  • Use the principle of least privilege when granting access to your buckets and objects.

    The principle of least privilege is a security guideline for granting privileges or rights. When you grant access based on the principle of least privilege you grant the minimum privilege that's necessary for a user to accomplish their assigned task. For example, if you want to share a file with someone, grant them READ permission and not FULL_CONTROL permission.

  • Avoid granting FULL_CONTROL permission to people you do not know.

    Granting FULL_CONTROL permission allows a user to change ACLs and take control of data. You should use the FULL_CONTROL permission only when you want to delegate administrative control over objects and buckets.

  • Be careful how you grant permissions for anonymous users.

    The AllUsers and AllAuthenticatedUsers scopes should only be used when it is acceptable for anyone on the Internet to read and analyze your data. While these are useful scopes for some applications and scenarios, it is usually not a good idea to grant all users FULL_CONTROL permission.

  • Avoid setting ACLs that result in inaccessible objects.

    An inaccessible object is an object that cannot be downloaded (read) and can only be deleted. This can happen when the owner of an object leaves a project without granting anyone else FULL_CONTROL or READ permission on the object. To avoid this problem, you can use the bucket-owner-read or bucket-owner-full-control predefined ACLs when you or anyone else uploads objects to your buckets.

  • Be sure you delegate administrative control of your buckets.

    By default, the project owners group is the only entity that has FULL_CONTROL permission on a bucket when it is created. You should have at least two members in the project owners group at any given time so that if a team member leaves the group, your buckets can still be managed by the other project owners.

Google Cloud Storage helps you adhere to these best practices by enforcing two ACL modification rules. Specifically, the ACL modification rules help prevent you setting ACLs that make data inaccessible. The ACL modification rules are as follows:

  • You cannot apply an ACL that specifies a different bucket or object owner.

    Bucket and object ownership cannot be changed by modifying ACLs. If you apply a new ACL to a bucket or object, be sure that the bucket or object owner remains unchanged in the new ACL.

  • The bucket or object owner will always have FULL_CONTROL permission of the bucket or object.

    The owner of a bucket is the project owners group, and the owner of an object is either the user who created the object, or the project owners group if the object was created by an anonymous user.

    When you apply a new ACL to a bucket or object, Google Cloud Storage will automatically add FULL_CONTROL permission to the bucket or object owner if you omit the grants. It will not grant the project owners group FULL_CONTROL permission for an object (unless the object was created by an anonymous user), so you must explicitly include it if you so desire.

Although you cannot apply ACLs that change the ownership of a bucket or object, you can change the ownership of objects by overwriting them. Overwriting is in effect a delete operation followed immediately by an upload operation. During an upload operation the person who is requesting the upload becomes the owner of the object. So, you can change the ownership of an object by having the new object owner overwrite the object. To overwrite an object the new object owner must have WRITE or FULL_CONTROL permission on the bucket in which the object resides. You cannot change bucket ownership under any circumstance.

Back to top

Signed URLs (Query String Authentication)

In some scenarios, you might not want to require your users to have a Google account in order to access Google Cloud Storage, but you still want to control access using your application-specific logic. The typical way to address this use case is to provide a signed URL to a user, which allows the user access to that resource for a limited time. Anyone who knows the URL can access the resource for a limited time. (You specify the expiration time in the query string to be signed.) Signed URLs can be generated for reading, writing, and deleting resources.

Overview of the Required Steps

To generate a signed URL, you need to the following:

  1. Construct the string to be signed.
  2. Sign the string using the RSA Algorithm.
  3. Assemble the URL.
  4. Share the URL with authorized users.

Signing by the RSA algorithm is supported for the Google Cloud Storage XML API. You can also sign URLs using HMAC when using the XML API for interoperable access.

Constructing the String to be Signed

The string to be signed has the following components:

StringToSign = HTTP_Verb + "\n" +
    Content_MD5 + "\n" +
    Content_Type + "\n" +
    Expiration + "\n" +
    Canonicalized_Extension_Headers +
    Canonicalized_Resource

These components are described in the following table:

String Component Description Example
HTTP_Verb Required. The verb to be used with the signed URL. Signed URLs can be used with GET, HEAD, PUT, and DELETE requests. Although Signed URLs cannot be used with POST, you can use the POST signature parameters described in POST Object to authenticate using web forms. GET
Content_MD5 Optional. The MD5 digest value in base64. If you provide this in the string, the client (usually a browser) must provide this HTTP header with this same value in its request. rmYdCNHKFXam78uCt7xQLw==
Content_Type Optional. If you provide this value the client (browser) must provide this HTTP header set to the same value. text/plain
Expiration Required. This is the timestamp (represented as the number of seconds since the Unix Epoch of 00:00:00 UTC on January 1, 1970) when the signature expires. The server will reject any requests received after this timestamp. 1388534400
Canonicalized_Extension_Headers Optional. If these headers are used, specify them in asciibetical order. The server will check to make sure that the client provides matching values. Be sure to remove any spaces between header names and header values. For information about how to create canonical headers for signing, see About Canonical Extension Headers. x-goog-acl:public-read\nx-goog-meta-foo:bar,baz\n
Canonicalized_Resource Required. The resource being addressed in the URL. For more details, see About Canonical Resources /bucket/objectname

The signature string for the example values in the above table would look like the following for a GET request. Note that newlines are shown as actual new lines here and in the next two examples.

GET


1388534400
/bucket/objectname

The signature string for the example values in the above table would look like the following for a PUT request.

PUT
rmYdCNHKFXam78uCt7xQLw==
text/plain
1388534400
x-goog-acl:public-read
x-goog-meta-foo:bar,baz
/bucket/objectname

Suppose a resumable upload has been initiated and it has returned a resumable session URI (uploadId), then you can create a string to be signed for a PUT request that will upload object data.

PUT

image/jpeg
1388534400
/bucket/objectname?uploadType=resumable&upload_id=uploadId

After you have constructed the string to sign, you must sign the string, and then assemble the URL using the signature.

About Canonical Extension Headers

You construct the Canonical Extension Headers portion of the message by concatenating all extension (custom) headers that begin with x-goog-. However, you cannot perform a simple concatenation. You must concatenate the headers using the following process:

  1. Make all custom header names lowercase.
  2. Sort all custom headers lexicographically by header name.
  3. Eliminate duplicate header names by creating one header name with a comma-separated list of values. Be sure there is no whitespace between the values and be sure that the order of the comma-separated list matches the order that the headers appear in your request. For more information, see RFC 2616 section 4.2.
  4. Replace any folding whitespace or newlines (CRLF or LF) with a single space. For more information about folding whitespace, see RFC 2822 section 2.2.3.
  5. Remove any whitespace around the colon that appears after the header name.
  6. Append a newline (U+000A) to each custom header.
  7. Concatenate all custom headers.

Important: You must use both the header name and the header value when you construct the Canonical Extension Headers portion of the query string. Be sure to remove any whitespace around the colon that separates the header name and value. For example, using the custom header x-goog-acl: private without removing the space after the colon will return a 403 Forbidden because the request signature you calculate will not match the signature Google calculates.

About Canonical Resources

You construct the Canonicalized_Resource portion of the message by concatenating the resource path (bucket and object and subresource) that the request is acting on. To do this, you can use the following process:

  1. Begin with an empty string.
  2. If the bucket name appears in the Host header, add a slash and the bucket name to the string (for example, /travel-maps). If the bucket name appears in the path portion of the HTTP request, do nothing.
  3. Add the path portion of the HTTP request to the string, excluding any query string parameters. For example, if the path is /europe/france/paris.jpg?cors and you already added the bucket travel-maps to the string, then you need to add /europe/france/paris.jpg to the string.
  4. If the request is scoped to a subresource, such as ?cors, add this subresource to the string, including the question mark.

Be sure to copy the HTTP request path literally: that is, you should include all URL encoding (percent signs) in the string that you create. Also, be sure that you include only query string parameters that designate subresources (such as cors). You should not include query string parameters such as ?prefix, ?max-keys, ?marker, and ?delimiter.

Signing Strings

Note: These instructions assume that you have created an OAuth client ID and private keys for a service account type application, as described in the Google Developers Console Help. If you have not already created those, please follow the help to create your client ID and private keys.

You sign the string you constructed using RSA signatures with SHA256 to authenticate requests. You will need these items in order to sign:

How to Sign

The following code is a self-contained, running example that you can use to sign a string, once you have the string constructed as described previously, private key, and email form of the client ID. You must have the Apache Commons Codec in order to run this sample.

The example below assumes that the downloaded pkcs12 file has the extension .p12 (for example, key.p12). The code takes three arguments: the path to the key, a password (notasecret), and that the data you want to sign.

Important: Each programming language and library has a different way of generating RSA signatures using SHA-256 as the hash function. Google Cloud Storage expects the Base64 encoded signature in its APIs. The GoogleAccessId is the email form of the Client Id.

A complete Python example can be found at the storage-signed-urls-python repository on GitHub.

Assembling the URL

After you construct the query string and sign it, you need to assemble the URL as follows:

  1. Create the base URL, which refers to the resource, making sure you use the same value as you used in the query string you just signed. Examples:
    • http://storage.googleapis.com/google-testbucket/testdata.txt
    • http://google-testbucket.storage.googleapis.com/testdata.txt
    • https://storage.googleapis.com/google-testbucket/testdata.txt
    • https://google-testbucket.storage.googleapis.com/testdata.txt
  2. URLencode the signature you created. (The Base64 encoded signature may contain characters not legal in URLs (specifically + and /). These values must be replaced by safe encodings (%2B and %2F, respectively).
  3. Concatenate the URL you want to distribute as follows:

    baseURL + "?GoogleAccessId=" + GoogleAccessStorageId + "&Expires=" + Expiration + "&Signature=" + UrlEncodedSignature

    where GoogleAccessStorageId is the email form of the client ID, and Expiration is the same value that you used in the query string you signed.

Here is a sample completed URL:

http://google-testbucket.storage.googleapis.com/testdata.txt?GoogleAccessId=1234567890123@developer.gserviceaccount.com&Expires=1331155464&Signature=BClz9e4UA2MRRDX62TPd8sNpUCxVsqUDG3YGPWvPcwN%2BmWBPqwgUYcOSszCPlgWREeF7oPGowkeKk7J4WApzkzxERdOQmAdrvshKSzUHg8Jqp1lw9tbiJfE2ExdOOIoJVmGLoDeAGnfzCd4fTsWcLbal9sFpqXsQI8IQi1493mw%3D

Back to top

Authentication required

You need to be signed in with Google+ to do that.

Signing you in...

Google Developers needs your permission to do that.