2
votes

I've created a service account and furnished with private key in JSON format (/adc.json). It can be loaded into google-cloud python client via Client.from_service_account_json function fine. But when I tried call the Monitoring API to write a custom metric, it's getting 403 error like below.

In [1]: from google.cloud import monitoring

In [2]: c = monitoring.Client.from_service_account_json('/adc.json')

In [6]: resource = client.resource('gce_instance', labels={'instance_id': '1234567890123456789', 'zone': 'us-central1-f'})

In [7]: metric = client.metric(type_='custom.googleapis.com/my_metric', labels={'status': 'successful'})

In [9]: from datetime import datetime

In [10]: end_time = datetime.utcnow()

In [11]: client.write_point(metric=metric, resource=resource, value=3.14, end_time=end_time)
---------------------------------------------------------------------------
Forbidden                                 Traceback (most recent call last)
<ipython-input-11-b030f6399aa2> in <module>()
----> 1 client.write_point(metric=metric, resource=resource, value=3.14, end_time=end_time)

/usr/local/lib/python3.5/site-packages/google/cloud/monitoring/client.py in write_point(self, metric, resource, value, end_time, start_time)
    599         timeseries = self.time_series(
    600             metric, resource, value, end_time, start_time)
--> 601         self.write_time_series([timeseries])

/usr/local/lib/python3.5/site-packages/google/cloud/monitoring/client.py in write_time_series(self, timeseries_list)
    544                            for timeseries in timeseries_list]
    545         self._connection.api_request(method='POST', path=path,
--> 546                                      data={'timeSeries': timeseries_dict})
    547 
    548     def write_point(self, metric, resource, value,

/usr/local/lib/python3.5/site-packages/google/cloud/_http.py in api_request(self, method, path, query_params, data, content_type, headers, api_base_url, api_version, expect_json, _target_object)
    301         if not 200 <= response.status < 300:
    302             raise make_exception(response, content,
--> 303                                  error_info=method + ' ' + url)
    304 
    305         string_or_bytes = (six.binary_type, six.text_type)

Forbidden: 403 User is not authorized to access the project monitoring records. (POST https://monitoring.googleapis.com/v3/projects/MY-PROJECT/timeSeries/)

In the GCP's Access Control Panel, I didn't see a specific predefined role scope for Stackdriver Monitoring API. See the screenshot below: enter image description here

I've tried Project Viewer, Service Account Actor predefined roles, neither worked. I am hesitatant to assigned a Project Editor role this service account because it feels like it's too broad of a scope for Stackdriver dedicated service account credential. So what should be the correct role to assign to this service account? Thanks.

1

1 Answers

3
votes

You are right that it's too broad, and we are working on finer-grained roles, but, as of today, "Project Editor" is the correct role.

If you are running on a GCE VM and omit the private key, the Stackdriver monitoring agent will by default attempt to use the VM's default service account. This will work as long as the VM has the https://www.googleapis.com/auth/monitoring.write scope (this should be turned on by default for all GCE VMs these days). See this page for a detailed description of what credentials the agent needs.