Skip to content

Commit f6bba7b

Browse files
committed
Adding auth doc explaining all the ways to mint credentials.
Fixes #633.
1 parent 96ee9d3 commit f6bba7b

File tree

3 files changed

+321
-32
lines changed

3 files changed

+321
-32
lines changed
Lines changed: 19 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,28 @@
1-
Now that you have a project,
2-
we need to make sure we are able to access our data.
3-
There are many ways to authenticate,
4-
but we're going to use a Service Account for today.
5-
6-
A *Service Account* is sort of like a username and password
7-
(like when you're connecting to your MySQL database),
8-
except the username is automatically generated
9-
(and is an e-mail address)
10-
and the password is actually a private key file.
1+
A `Service Account`_ handles authentication for a backend service that
2+
needs to talk to other services (e.g. Google APIs).
113

124
To create a Service Account:
135

14-
* **Click on Credentials**
15-
under the "APIs & Auth" section.
16-
17-
* **Click the big red button**
18-
that says "Create New Client ID"
19-
under the OAuth section
20-
(the first one).
6+
#. Visit the `Google Developers Console`_.
217

22-
* **Choose "Service Account"**
23-
and click the blue button
24-
that says "Create Client ID".
8+
#. Create a new project or click on an existing project.
259

26-
* **This will automatically**
27-
download a private key file.
28-
**Do not lose this.**
10+
#. Navigate to **APIs & auth** > **APIs section** and turn on the following
11+
APIs (you may need to enable billing in order to use these services):
2912

30-
* **Rename your key** something shorter.
31-
I like to name the key ``<project name>.p12``.
13+
* Google Cloud Datastore API
14+
* Google Cloud Storage
15+
* Google Cloud Storage JSON API
16+
* Google Pub/Sub API
3217

33-
This is like your password for the account.
18+
#. Navigate to **APIs & auth** > **Credentials** and then:
3419

35-
* **Copy the long weird e-mail address**
36-
labeled "E-mail address"
37-
in the information section
38-
for the Service Account
39-
you just created.
20+
* If you want to use a new service account, click on **Create new Client ID**
21+
and select **Service account**. After the account is created, you will be
22+
prompted to download the JSON key file that the library uses to authorize
23+
your requests.
24+
* If you want to generate a new key for an existing service account, click
25+
on **Generate new JSON key** and download the JSON key file.
4026

41-
This is like your username for the account.
27+
.. _Google Developers Console: https://console.developers.google.com/project
28+
.. _Service Account: https://developers.google.com/accounts/docs/OAuth2ServiceAccount

docs/gcloud-auth.rst

Lines changed: 301 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
1+
.. toctree::
2+
:maxdepth: 1
3+
:hidden:
4+
5+
GCloud Auth
6+
-----------
7+
8+
For the majority of cases, authentication with the ``gcloud`` library
9+
will **"just work"**. Credentials are loaded implicitly from the environment
10+
where the code is running and **no code** is required to enable authentication
11+
within your code.
12+
13+
The core :mod:`gcloud.credentials` module provides helper methods
14+
for any account type needed.
15+
16+
A production application should **use a service account**, but you may
17+
wish to use your own personal user account when first getting started with
18+
the ``gcloud`` library.
19+
20+
=============
21+
Basic Example
22+
=============
23+
24+
With an environment set up to use `Google Default Credentials`_, your
25+
API requests will be authenticated automatically:
26+
27+
.. code-block:: python
28+
29+
from gcloud import datastore
30+
from gcloud import pubsub
31+
from gcloud import storage
32+
33+
entities = datastore.get([
34+
datastore.Key('EntityKind', 1, dataset_id='foo')])
35+
36+
bucket = storage.get_bucket('bucket-name')
37+
38+
pubsub.Topic('topic_name', project_id='my.project').create()
39+
40+
=============
41+
Advanced Uses
42+
=============
43+
44+
A custom connection can be used as the default, but will need to be
45+
explicitly set. The
46+
:func:`set_default_connection() <gcloud.datastore.__init__.set_default_connection>`
47+
function is provided in all sub-packages to set a connection. For
48+
example, in the ``datastore`` sub-package:
49+
50+
.. code-block:: python
51+
52+
credentials = get_custom_credentials()
53+
connection = datastore.Connection(credentials=credentials)
54+
datastore.set_default_connection(connection)
55+
56+
# ... Create keys.
57+
entities = datastore.get([key1, key2])
58+
59+
If no default is set, all functions which make a connection to an API
60+
accept an optional ``connection`` argument. For example, with ``datastore``,
61+
the implicit behavior can be duplicated with:
62+
63+
.. code-block:: python
64+
65+
from gcloud.credentials import get_credentials
66+
67+
credentials = get_credentials().create_scoped(datastore.SCOPE)
68+
connection = datastore.Connection(credentials=credentials)
69+
70+
# ... Create keys.
71+
entities = datastore.get([key1, key2], connection=connection)
72+
73+
If no connection is passed explicity and
74+
:func:`set_default_connection() <gcloud.datastore.__init__.set_default_connection>`
75+
is never called, the request will fail:
76+
77+
.. code-block:: python
78+
79+
Traceback (most recent call last):
80+
File "<stdin>", line 1, in <module>
81+
File "gcloud/datastore/api.py", line 200, in get
82+
connection = _require_connection(connection)
83+
File "gcloud/datastore/api.py", line 82, in _require_connection
84+
raise EnvironmentError('Connection could not be inferred.')
85+
EnvironmentError: Connection could not be inferred.
86+
87+
---------------------------------
88+
Multiple Simultaneous Connections
89+
---------------------------------
90+
91+
Some applications will need to read and write data into multiple projects.
92+
This may require using more than one set of credentials (either via JSON key
93+
files or other means).
94+
95+
As a result, a single connection will be insufficient to make all API requests.
96+
To use two separate connections, proceed as above by using explicit connections
97+
in each function that makes an API request:
98+
99+
.. code-block:: python
100+
101+
credentials1 = my_custom_credentials_function('foo')
102+
credentials2 = my_custom_credentials_function('bar')
103+
104+
connection1 = datastore.Connection(credentials=credentials1)
105+
connection2 = datastore.Connection(credentials=credentials2)
106+
107+
key1 = datastore.Key('CompanyA', 1337, dataset_id='foo')
108+
entities1 = datastore.get([key1], connection=connection1)
109+
110+
key2 = datastore.Key('CompanyB', 42, dataset_id='bar')
111+
datastore.delete([key2], connection=connection2)
112+
113+
If one is connection used more often than another, it can still be used as the
114+
default:
115+
116+
.. code-block:: python
117+
118+
datastore.set_default_connection(connection=connection1)
119+
120+
entities1 = datastore.get([key1])
121+
122+
datastore.delete([key2], connection=connection2)
123+
124+
=======================
125+
Supported Account Types
126+
=======================
127+
128+
With the helper functions provided, we support the following
129+
OAuth 2.0 account types:
130+
131+
- Google `App Engine Service Accounts`_
132+
- Google `Compute Engine Service Accounts`_
133+
- `Service Accounts`_ with JSON `Service Account Key`_
134+
- User Accounts (3-legged `OAuth`_ 2.0) with refresh token
135+
- Service Accounts with PKCS12 / P12 `Service Account Key`_
136+
137+
==========================
138+
Google Default Credentials
139+
==========================
140+
141+
All but one `supported account type`_ listed above can be handled by using
142+
Google `Application Default`_ credentials via
143+
:func:`get_credentials() <gcloud.credentials.get_credentials>`. This function
144+
can be used directly to obtain ``credentials`` to be passed
145+
to a ``Connection`` or can be used implictly by calling
146+
:func:`get_connection (datastore) <gcloud.datastore.__init__.get_connection>`
147+
and :func:`get_connection (storage) <gcloud.storage.__init__.get_connection>`.
148+
149+
----------------------------------
150+
Google App Engine Service Accounts
151+
----------------------------------
152+
153+
:func:`get_credentials() <gcloud.credentials.get_credentials>`
154+
implicitly handles **Google App Engine Service Accounts** with no user
155+
intervention required.
156+
157+
To explicitly load these credentials:
158+
159+
.. code-block:: python
160+
161+
from oauth2client.appengine import AppAssertionCredentials
162+
credentials = AppAssertionCredentials([])
163+
164+
--------------------------------------
165+
Google Compute Engine Service Accounts
166+
--------------------------------------
167+
168+
:func:`get_credentials() <gcloud.credentials.get_credentials>` implicitly
169+
handles **Google Compute Engine Service Accounts** with no user intervention
170+
required. However, when creating the `instance`_, the service account
171+
must be enabled and the correct set of scopes must be selected for
172+
the services you intend to use.
173+
174+
To explicitly load these credentials:
175+
176+
.. code-block:: python
177+
178+
from oauth2client.gce import AppAssertionCredentials
179+
credentials = AppAssertionCredentials([])
180+
181+
.. _instance: https://cloud.google.com/compute/docs/instances
182+
183+
-------------------------------
184+
Service Accounts with JSON keys
185+
-------------------------------
186+
187+
As mentioned above, support for **Service Accounts with JSON keys** can be done
188+
by setting the ``GOOGLE_APPLICATION_CREDENTIALS`` environment variable:
189+
190+
.. code-block:: bash
191+
192+
$ export GOOGLE_APPLICATION_CREDENTIALS="/path/to/key_file.json"
193+
194+
If you'd like to load these credentials explicitly rather than via the
195+
environment, you can use
196+
:func:`get_for_service_account_json() <gcloud.credentials.get_for_service_account_json>`:
197+
198+
.. code-block:: python
199+
200+
from gcloud.credentials import get_for_service_account_json
201+
202+
private_key_path = '/path/to/key_file.p12'
203+
204+
credentials = get_for_service_account_json(private_key_path)
205+
206+
-------------------------------------------------
207+
User Accounts (3-legged OAuth) with refresh token
208+
-------------------------------------------------
209+
210+
As mentioned in the introduction, a production application should
211+
**use a service account**. However, when just getting started with the library,
212+
it can be useful to just use an authorized user account.
213+
214+
If you've installed the ``gcloud`` command line `tool`_, you can authorize
215+
a user account by running
216+
217+
.. code-block:: bash
218+
219+
$ gcloud auth login
220+
221+
(it's very likely you've already done so).
222+
223+
.. _tool: https://cloud.google.com/sdk/gcloud/
224+
225+
After doing so, you can re-use these credentials within ``gcloud``
226+
just by using :func:`get_credentials() <gcloud.credentials.get_credentials>`:
227+
228+
.. code-block:: python
229+
230+
from gcloud.credentials import get_credentials
231+
credentials = get_credentials()
232+
233+
.. note::
234+
235+
The ``gcloud`` CLI tool will create an authorized user JSON credentials
236+
file on your system. On \*nix systems, this will typically reside in
237+
``${HOME}/.config/gcloud/application_default_credentials.json``.
238+
239+
In addition to using the credentials from the ``gcloud`` CLI, you can use your
240+
own credentials file. This file will contain a JSON object with four keys:
241+
242+
.. code-block:: json
243+
244+
{
245+
"client_id": "123",
246+
"client_secret": "secret",
247+
"refresh_token": "FOO",
248+
"type": "authorized_user"
249+
}
250+
251+
This can be used just as a JSON key file can be used for a service account
252+
253+
.. code-block:: bash
254+
255+
$ export GOOGLE_APPLICATION_CREDENTIALS="/path/to/authorized_user_credentials.json"
256+
257+
As with Service Accounts with JSON keys, you can explicitly load an authorized
258+
user account key with
259+
:func:`get_for_service_account_json() <gcloud.credentials.get_for_service_account_json>`.
260+
261+
=================================
262+
PKCS12 / P12 Service Account Keys
263+
=================================
264+
265+
PKCS12 / P12 Service Account keys are the only `supported account type`_ above
266+
that is not covered by Google Default Credentials.
267+
268+
.. _supported account type: #supported-account-types
269+
270+
This is because **JSON Service Account Credentials** are the preferred format.
271+
272+
If for some reason you need (or want) to use a P12 key,
273+
:func:`get_for_service_account_p12() <gcloud.credentials.get_for_service_account_p12>`
274+
allows you to load service account credentials for such a key:
275+
276+
.. code-block:: python
277+
278+
from gcloud.credentials import get_for_service_account_p12
279+
280+
client_email = '[email protected]'
281+
private_key_path = '/path/to/key_file.p12'
282+
283+
credentials = get_for_service_account_p12(client_email, private_key_path)
284+
285+
Notice that unlike the JSON Service Account Key, the P12 key also
286+
**requires the email address** for the service account. (This is because the
287+
JSON key file contains the email address, while the P12 key file only contains
288+
the private key bytes.)
289+
290+
==========================
291+
Enabling a service account
292+
==========================
293+
294+
.. include:: _components/enabling-a-service-account.rst
295+
296+
.. _Service Account Key: https://cloud.google.com/storage/docs/authentication#generating-a-private-key
297+
.. _Application Default: https://developers.google.com/accounts/docs/application-default-credentials
298+
.. _App Engine Service Accounts: https://cloud.google.com/appengine/docs/python/appidentity/
299+
.. _Compute Engine Service Accounts: https://cloud.google.com/compute/docs/authentication#metadata
300+
.. _OAuth: https://developers.google.com/accounts/docs/OAuth2WebServer
301+
.. _Service Accounts: #enabling-a-service-account

docs/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
:hidden:
44

55
gcloud-api
6+
gcloud-auth
67
datastore-api
78
datastore-entities
89
datastore-keys

0 commit comments

Comments
 (0)