If your architecture is using multiple services, these services will likely need to communicate with each other.
You can use synchronous or asynchronous service-to-service communication:
For asynchronous communication, use
- Cloud Tasks for one to one asynchronous communication
- Pub/Sub for one to many asynchronous communication
For synchronous communication, one service invokes another one over
HTTP using its endpoint URL. In this use case, it's a good idea to ensure that each
service is only able to make requests to specific services.
For instance, if you have a login
service, it should be able to access the
user-profiles
service, but it probably shouldn't be able to access the
search
service.
First, you'll need to configure the receiving service to accept requests from the calling service:
- Grant the Cloud Run Invoker (
roles/run.invoker
) role to the calling service identity on the receiving service. By default, this identity isPROJECT_NUMBER-compute@developer.gserviceaccount.com
.
Console UI
Go to the Google Cloud Console:
Select the receiving service.
Click Show Info Panel in the top right corner to show the Permissions tab.
In the Add members field, enter the identity of the calling service.
Select the
Cloud Run Invoker
role from the Select a role drop-down menu.Click Add.
GCloud
Use the gcloud run services add-iam-policy-binding
command:
gcloud run services add-iam-policy-binding RECEIVING_SERVICE \ --member='serviceAccount:CALLING_SERVICE_IDENTITY' \ --role='roles/run.invoker'
where RECEIVING_SERVICE
is the name of the receiving
service, and CALLING_SERVICE_IDENTITY
is the email
address of the service account.
In the calling service, you'll need to:
Create a Google-signed OAuth ID token with the audience (
aud
) set to the URL of the receiving service. This value must contain the schema prefix (http://
orhttps://
) and custom domains are currently not supported for theaud
value.Include the ID token in an
Authorization: Bearer ID_TOKEN
header in the request to the service.
Nodejs
// Make sure to `npm install --save request-promise` or add the dependency to your package.json const request = require('request-promise'); const receivingServiceURL = ... // Set up metadata server request // See https://cloud.google.com/compute/docs/instances/verifying-instance-identity#request_signature const metadataServerTokenURL = 'http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience='; const tokenRequestOptions = { uri: metadataServerTokenURL + receivingServiceURL, headers: { 'Metadata-Flavor': 'Google' } }; // Fetch the token, then provide the token in the request to the receiving service request(tokenRequestOptions) .then((token) => { return request(receivingServiceURL).auth(null, null, true, token) }) .then((response) => { res.status(200).send(response); }) .catch((error) => { res.status(400).send(error); });
Python
# Requests is already installed, no need to add it to requirements.txt import requests receiving_service_url = ... # Set up metadata server request # See https://cloud.google.com/compute/docs/instances/verifying-instance-identity#request_signature metadata_server_token_url = 'http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience=' token_request_url = metadata_server_token_url + receiving_service_url token_request_headers = {'Metadata-Flavor': 'Google'} # Fetch the token token_response = requests.get(token_request_url, headers=token_request_headers) jwt = token_response.content.decode("utf-8") # Provide the token in the request to the receiving service receiving_service_headers = {'Authorization': f'bearer {jwt}'} service_response = requests.get(receiving_service_url, headers=receiving_service_headers) return service_response.content
Go
Calling from outside GCP
If you're invoking a service from a compute instance that doesn't have access to compute metadata (e.g. your own server), you'll have to manually generate the proper token:
Self-sign a service account JWT with the
target_audience
claim set to the URL of the receiving service.Exchange the self-signed JWT for a Google-signed ID token, which should have the
aud
claim set to the above URL.Include the ID token in an
Authorization: Bearer ID_TOKEN
header in the request to the service.
The Cloud IAP docs have sample code to demonstrate this functionality.