Introduction
This article describes a missing item from the articles and documentation on Google Cloud Asset Inventory. The item is the header X-Goog-User-Project
. I am writing this article to show how I figured this out, so you have another method to figure out missing or incorrect documentation.
Google’s description of Cloud Asset Inventory (link):
Cloud Asset Inventory provides inventory services based on a time series database. This database keeps a five-week history of Google Cloud Platform (GCP) asset metadata. The Cloud Asset Inventory export service allows you to export all asset metadata at a certain timestamp or export event change history during a timeframe.
Google Cloud released Cloud Asset Inventory as GA on April 3, 2019. If your job is security, auditing or compliance (to name a few), then this service is important and can make your job easier. Google Cloud has 100+ services and trying to figure out what is running and where is challenging. Cloud Asset Inventory is a new tool that helps you manage cloud resources.
The Problem
In following along with this article and studying this documentation, I could not get the curl examples to work. The CLI commands worked.
My system is Windows 10. The commands are almost identical for Linux:
- Change the line continuation character from ^ to \
- Change variables from %TOKEN% to $TOKEN
I used this command to generate the OAuth token for the curl commands:
1 2 |
gcloud auth print-access-token > auth.token set /p TOKEN=<auth.token |
For Linux use:
1 |
$TOKEN=`gcloud auth print-access-token` |
Example curl command:
1 2 3 4 |
curl https://cloudasset.googleapis.com/v1/projects/development-123456:exportAssets?alt=json ^ -H "Authorization: Bearer %TOKEN%" ^ -H "Content-Type: application/json" ^ -d "{\"outputConfig\":{\"gcsDestination\":{\"uri\":\"gs://development-123456/assets.json\"}}}" |
No matter what I tried I received this error:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
{ "error": { "code": 400, "message": "Invalid output GCS file path in request or permission denied", "status": "INVALID_ARGUMENT", "details": [ { "@type": "type.googleapis.com/google.rpc.BadRequest", "fieldViolations": [ { "field": "output_config.gcs_destination.uri", "description": "Invalid output GCS file path in request or permission denied" } ] } ] } } |
This error had me trying over and over. I double check the path; I double check my auth token; I experimented. Then I remembered the command-line option --log-http
. Let’s see what the CLI does.
The Research
The curl examples did not work, but the CLI examples worked. This means that the Asset Inventory service works, there is just an issue with the curl commands. The CLI has a command-line option --log-http
that logs all HTTP server requests and responses to stderr. You can also set the config option core/log_http
.
Example Command:
1 2 3 |
gcloud --log-http asset export ^ --output-path=gs://development-123456/assets.json ^ --project=development-123456 |
This resulted in the following output (truncated):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
======================= ==== request start ==== uri: https://cloudasset.googleapis.com/v1/projects/development-123456:exportAssets?alt=json method: POST == headers start == Authorization: --- Token Redacted --- X-Goog-User-Project: development-123456 accept: application/json accept-encoding: gzip, deflate content-length: 128 content-type: application/json user-agent: google-cloud-sdk x_Tw5K8nnjoRAqULM9PFAC2b gcloud/249.0.0 command/gcloud.asset.export invocation-id/a7cb18ae35c9403bb42da7d5ad3f68f9 environment/None environment-version/None interactive/False from-script/False python/2.7.13 term/ (Windows NT 10.0.17763) == headers end == == body start == {"contentType": "CONTENT_TYPE_UNSPECIFIED", "outputConfig": {"gcsDestination": {"uri": "gs://development-123456/assets.txt"}}} == body end == ==== request end ==== |
In studying the output, I noticed this line:
1 |
X-Goog-User-Project: development-123456 |
I then did a Google search and the only place I could find this header mentioned is here. The description for this header: “A request header that specifies a user project to bill for access charges associated with the request”. A first review of this description made little sense to me. Then I remembered that Google Cloud supports organizations and multiple billing accounts. Maybe this header is required for billing. Hmm, let’s try this header.
The Solution:
I then added this header to the curl command:
1 2 3 4 5 |
curl https://cloudasset.googleapis.com/v1/projects/development-123456:exportAssets?alt=json ^ -H "Authorization: Bearer %TOKEN%" ^ -H "Content-Type: application/json" ^ -H "X-Goog-User-Project: development-123456" ^ -d "{\"outputConfig\":{\"gcsDestination\":{\"uri\":\"gs://development-123456/assets.json\"}}}" |
This resulted in the following output:
1 2 3 4 5 6 7 8 9 10 11 12 |
{ "name": "projects/123456785923/operations/ExportAssets/CONTENT_TYPE_UNSPECIFIED/123456785256952138", "metadata": { "@type": "type.googleapis.com/google.cloud.asset.v1.ExportAssetsRequest", "parent": "projects/123456785923", "outputConfig": { "gcsDestination": { "uri": "gs://development-123456/assets2.json" } } } } |
Success.
This command runs asynchronously. In a few minutes, the asset inventory is written to Cloud Storage. The file format is Newline Delimited JSON. The output looks like this (truncated):
1 2 3 |
{"name":"//cloudsql.googleapis.com/projects/development-123456/instances/cloudrun-sql","asset_type":"sqladmin.googleapis.com/Instance"} {"name":"//compute.googleapis.com/projects/c/global/firewalls/allow-http-ssh","asset_type":"compute.googleapis.com/Firewall"} {"name":"//compute.googleapis.com/projects/development-123456/global/instanceTemplates/kubernetes-minion-template","asset_type":"compute.googleapis.com/InstanceTemplate"} |
Summary
Cloud Asset Inventory looks to be a great product for Google Cloud. I intend to spend a lot more time digging into its features and options.
Whenever you are trying to figure out an API, use the CLI to prototype. Use the --log-http
command-line option to create output that can help you figure out what the API really requires by referencing a real-world example.
Reverse Engineering is both an art and a skill. For those of us that worked in the days of MS-DOS and Microsoft Windows, we would spend hours/days/months figuring out undocumented features so we could design competitive products. These skills result from thousands of hours of digging into a product/service/technology repeatedly.
More Information
- Documentation on –log-http
- Documentation on X-Goog-User-Project
- Introduction to Cloud Asset Inventory
- Using the Google Cloud SDK
- Cloud Asset Inventory Quickstart
- Cloud SDK gcloud asset
- Article: Gain insights about your GCP resources with asset inventory – October 8, 2018
- Article: Cloud Asset Inventory: Easier inventory management, security analysis and config monitoring – June 4, 2019
- GitHub: Cloud Asset Inventory Import To BigQuery
- REST API: Method: exportAssets
- Spotify Labs: Painting a Picture of Your Infrastructure in Minutes – June 4, 2019
Credits
I write free articles about technology. Recently, I learned about Pexels.com which provides free images. The image in this article is courtesy of Pixabay at Pexels.
I design software for enterprise-class systems and data centers. My background is 30+ years in storage (SCSI, FC, iSCSI, disk arrays, imaging) virtualization. 20+ years in identity, security, and forensics.
For the past 14+ years, I have been working in the cloud (AWS, Azure, Google, Alibaba, IBM, Oracle) designing hybrid and multi-cloud software solutions. I am an MVP/GDE with several.
Leave a Reply