There are two ways to control access to Google Cloud Storage objects and buckets:
- Access Control Lists (ACLs) , which uses Google accounts and provides longer term access.
- Signed URLs (Query String Authentication) , which does not use Google accounts, but provides "valet-key" type access for a limited time.
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
- Scopes and permissions
- Understanding default bucket and object ACLs
- Specifying bucket and object ACLs
- Managing access control
- Signed URLs (query string authentication)
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: [email protected]. 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:
- Go to the Google Developers Console .
- Select a project by clicking its name.
- Click Cloud Storage , and then click Project dashboard .
- The IDs are in the Google Cloud Storage IDs section.
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 thanFULL_CONTROL
permission to the owner, Google Cloud Storage automatically escalates the permission toFULL_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
groupWRITE
orFULL_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>[email protected]</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 theOwner
element in advance. Google Cloud Storage supplies theOwner
element and grantsFULL 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>
Specifying bucket and object ACLs
There are three ways to specify ACLs to buckets and objects, using:
- The acl query string parameter to specify ACLs for certain scopes
- The x-goog-acl request header to specify predefined ACLs
- The defaultObjectACL query string parameter to change the default object ACL for all objects in a certain bucket
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 [email protected]
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>[email protected]</EmailAddress> <Name>Jane</Name> </Scope> <Permission>FULL_CONTROL
</Permission> </Entry> <Entry> <Scope type="GroupByEmail"> <EmailAddress>[email protected]</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
[email protected]
. 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>[email protected]</EmailAddress>
<Name>Jane</Name>
</Scope>
<Permission>FULL_CONTROL
</Permission>
</Entry>
These optional
<Name>
elements are populated in one of two ways:
-
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. -
A
UserByEmail
orGroupByEmail
scope was used with a public Google profileIf 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 <<em>12345 bytes in entity body</i>>
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 <<em>empty entity body</em>>
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 notFULL_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
andAllAuthenticatedUsers
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 usersFULL_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
orREAD
permission on the object. To avoid this problem, you can use thebucket-owner-read
orbucket-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 groupFULL_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.
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.
Creating a signed URL with gsutil
The
gsutil
tool includes the
signurl
command to quickly create signed URLs.
To create a signed URL with gsutil:
- Make sure you have a Private Key you can use. If you don't, you can follow the steps in Service Account Authentication to create one.
-
Use the
signurl
command and specify at least the path to the Private Key and the bucket. For example, you can use the following command to generate a signed URL for users to view the objectfoo
object for 10 minutes.$ gsutil signurl -d 10m path/to/privatekey.p12 gs://bucket/foo
The command above will prompt you for the keystore password, which is "notasecret". You can also use the
-p
flag to specify the password in the command. For help on other options, including how to specify different HTTP methods for which to create the signed URL, display help withgsutil signurl --help
.
Creating a signed URL step-by-step
Overview of the required steps
To generate a signed URL, you need to the following:
- Construct the string to be signed.
- Sign the string using the RSA Algorithm .
- Assemble the URL .
- 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, the server will check to make sure that the client provides matching 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:
- Make all custom header names lowercase.
- Sort all custom headers by header name using a lexicographical sort by code point value.
- 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.
- 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.
- Remove any whitespace around the colon that appears after the header name.
- Append a newline (U+000A) to each custom header.
- 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:
- Begin with an empty string.
-
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. -
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. -
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:
- The String to Sign , described previously.
- Client ID and Private Key, which you can get from following the steps in Service Account Authentication .
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 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:
-
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
-
-
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). -
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, andExpiration
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