You can implement authentication between services by using a service account in a gRPC service. This page demonstrates service-to-service authentication by walking you through a complete example, including how to configure the Extensible Service Proxy (ESP) in a gRPC service to support authenticated requests and how to call the service from a gRPC client.
In order for any service to make authenticated calls into an Cloud Endpoints
API, the calling service must have a
service account
and it must send an auth token in the call. The caller must use a
Google ID token
or a custom
JSON Web Token (JWT) that is signed only
by the service account of the caller. ESP validates that the
iss
claim in the JWT matches the issuer
setting in the service
configuration. ESP doesn't
check for Identity and Access Management
permissions that have been granted on the service account.
In our example, you set up and use the simplest form of service-to-service authentication, where the client uses their Google Cloud service account to generate authenticating JWTs. The approach for other authentication methods is similar, though the client-side process for getting valid authentication tokens depends on the authentication method used.
Before you begin
This guide uses the Bookstore example used in our Tutorials.
Clone the git repo where the gRPC example code is hosted:
git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git
Change your working directory:
cd python-docs-samples/endpoints/bookstore-grpc/
Follow the instructions in the Tutorials to set up a project if you don't have one already.
In this example, you use deployment to Google Kubernetes Engine, though the authentication setup is the same for Compute Engine.
In the example, there are two Google Cloud Platform projects that are referenced:
- The service producer project, which is the project that owns the Cloud Endpoints for gRPC service.
- The service consumer project, which is the project that owns the gRPC client.
Creating the consumer service account and key
To create the service account and key for the consumer project:
- In the Google Cloud console, go to APIs & services. Make sure you are in your consumer project.
- On the Credentials page, in the Create Credentials drop-down list, select Service Account Key.
On the Create service account key page, if you have an existing service account that you'd like to use, select it. Otherwise, in the Service account drop-down list, select New service account and type an account name.
A corresponding Service account ID is created for you. Make note of the ID, as it is needed in the following sections. For example:
service-account-name@YOUR_PROJECT_ID.iam.gserviceaccount.com
Click the Role drop-down list and select the following roles:
- Service Accounts > Service Account User
- Service Accounts > Service Account Token Creator
Ensure the JSON key type is selected.
Click Create. Your service account JSON key file is downloaded to your local machine. Note the location and make sure it's stored securely because it is used later to generate tokens.
Configuring authentication for the service
Use the producer project for all steps in this section.
Set up authentication in the gRPC API configuration
Authentication for ESP is configured in the authentication
section of your gRPC API configuration YAML file. The configuration with
authentication for this example service is in
api_config_auth.yaml
.
The providers
section specifies the authentication provider(s) you want to
use - in this case, that you want to use a Google service account as an
authentication provider. The rules
section specifies that you require tokens
from this provider for access to all your service's methods.
In your own copy of this file from the cloned repo:
- Change
MY_PROJECT_ID
to your producer project ID. - Change
SERVICE-ACCOUNT-ID
in theauthentication
section (in both theissuer
andjwks_uri
values) to the consumer service account ID you noted in the previous section. This tells ESP that you want to grant access to your service to users who provide valid tokens from this particular service account. - Optionally, add
jwt_locations
under theproviders
element. You can use this value to define a custom JWT location. The default JWT locations are theAuthorization
metadata (prefixed by "Bearer ") and theX-Goog-Iap-Jwt-Assertion
metadata.
Save the file for the next step.
Deploy the configuration and service
These steps are the same as in Getting started with gRPC on GKE:
Deploy your service configuration to Endpoints: you need to do this even if you did so for the tutorial, as this is a different configuration. Note the returned service name:
gcloud endpoints services deploy api_descriptor.pb api_config_auth.yaml --project PRODUCER_PROJECT
Create a container cluster and authenticate
kubectl
to the cluster, if you haven't already done so.Deploy the sample API and ESP to the cluster. If you are using separate producer and consumer projects, first make sure that you have set the appropriate project within the
gcloud
command-line tool:gcloud config set project PRODUCER_PROJECT
Calling authenticated methods from a gRPC client
Finally, on the client side, you can use the service account key to generate a
JWT token and then use the token to call an authenticated Bookstore method.
First install the appropriate Python requirements to both generate the token and
run the example client. Ensure that you are in the
python-docs-samples/endpoints/bookstore-grpc
folder of your cloned client, then:
virtualenv bookstore-env
source bookstore-env/bin/activate
pip install -r requirements.txt
Generate a JWT token
In this example, the Bookstore is using service-to-service authentication where the calling service is purely authenticated by its service account, so creating an appropriate token to send with our requests is simple. Note that you can also require more stringent service-to-service authentication where the generated token must be further authenticated by Google (using a Google Id token).
For this example, the provided Python script can generate a token from the JSON key file downloaded earlier, using a dummy user ID and email.
To generate a token using the script:
Generate a JWT token and assign it to the variable
$JWT_TOKEN
:JWT_TOKEN=$(python jwt_token_gen.py \ --file=[SERVICE_ACCOUNT_FILE] \ --audiences=[SERVICE_NAME] \ --issuer=[SERVICE-ACCOUNT-ID])
where:
[SERVICE_ACCOUNT_FILE]
is the downloaded consumer service account JSON key file.[SERVICE_NAME]
is the name of the Bookstore service that was returned when you deployed its updated service configuration to Endpoints.[SERVICE-ACCOUNT-ID]
is the full consumer service account ID when you generated your service account.
Make an authenticated gRPC call
This last step uses
bookstore_client.py
,
which is the same client used in the
Tutorials. To make an authenticated call, the
client passes the JWT as
metadata with their
method call.
To run the example:
Use
kubectl get services
to get the external IP address for the deployed Bookstore:#kubectl get services NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE echo 10.11.246.240 104.196.186.92 80/TCP 10d endpoints 10.11.243.168 104.196.210.50 80/TCP,8090/TCP 10d esp-grpc-bookstore 10.11.254.34 104.196.60.37 80/TCP 1d kubernetes 10.11.240.1 <none> 443/TCP 10d
In this case, it's the
esp-grpc-bookstore
service and its external IP is104.196.60.37
.Assign the IP address to the variable
EXTERNAL_IP
EXTERNAL_IP=104.196.60.37
List all the shelves from the Bookstore service:
python bookstore_client.py --port=80 --host=$EXTERNAL_IP --auth_token=$JWT_TOKEN
The service returns all the shelves in the current Bookstore. You can double check it by not providing a token, or by specifying the wrong service account ID when generating the JWT. The command should fail.