Architecture Overview

The inventory job runs as a Cloud Run Job on a configurable schedule inside the target GCP project. It reads from five GCP service APIs, writes six JSON artifacts to a GCS bucket, and promotes them to a latest/ prefix. The OpenICF connector in PingOne IDM reads those artifacts (plus live Dialogflow CX / Vertex AI Agent Engine APIs) to surface AI governance data during reconciliation.

Vertex inventory Cloud Run Job architecture diagram Shows the inventory job reading from Dialogflow CX, Vertex AI Agent Engine, Cloud Resource Manager, IAM, and Cloud Trace/Logging APIs, writing artifacts to GCS, with the OpenICF connector consuming from both GCS and live APIs. GCP PROJECT Dialogflow CX Vertex AI Agent Engine Cloud Resource Mgr IAM Cloud Trace / Logging Agents, webhooks Reasoning engines Project IAM (fallback) SA metadata, keys Activity logs, spans vertex-tools -inventory Cloud Run Job Β· Python 3.12 Scheduled (Cloud Scheduler) GCS Inventory Bucket Uniform bucket-level access agents.json identity-bindings.json service-accounts.json tool-credentials.json activity-logs.json manifest.json written last runs/<ts>/ β†’ latest/ upload_from _filename PINGONE IDM / OPENIDM HOST OpenICF Connector googlevertexai-connector (Java) Reconciliation β†’ IGA platform GetObject (ADC bearer) Live: ListAgents, GetAgent, ListRE, GetGuardrail… LEGEND Job reads GCS write / read Connector live API

Shell Variables

All commands reference shell variables. Set these in your terminal before running anything. Later steps capture additional values as resources are created.

bash β€” environment setup
export PROJECT_ID=<your-gcp-project-id>
export REGION=us-central1

export BUCKET_NAME=${PROJECT_ID}-vertex-inventory
export JOB_SA_NAME=vertex-inventory-job
export JOB_SA_EMAIL=${JOB_SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com
export AR_REPO=vertex-inventory
export IMAGE=${REGION}-docker.pkg.dev/${PROJECT_ID}/${AR_REPO}/vertex-tools-inventory:latest
export JOB_NAME=vertex-tools-inventory
export FLAVOR=both
Config via environment variable
The Cloud Run Job receives its configuration as the INVENTORY_CONFIG_JSON environment variable. No config file mount or GCS volume is required.

Prerequisites

Before starting, ensure you have:

The two prerequisite steps (P1–P2) must complete before Step 1.

P1 Install Required Tools

Install the Google Cloud SDK and Docker. These are the only local dependencies β€” no Python installation is needed (the job runs in a container).

P1a β€” Google Cloud SDK

Follow https://cloud.google.com/sdk/docs/install for your operating system, then authenticate:

bash
gcloud auth login
gcloud config set project ${PROJECT_ID}

P1b β€” Docker

Follow https://docs.docker.com/get-docker/. Verify the daemon is running:

bash
docker info

P2 Enable Required APIs

Enable all GCP APIs used by the job and the deployment pipeline in a single command:

bash
gcloud services enable \
  artifactregistry.googleapis.com \
  run.googleapis.com \
  iam.googleapis.com \
  dialogflow.googleapis.com \
  aiplatform.googleapis.com \
  cloudresourcemanager.googleapis.com \
  storage.googleapis.com \
  cloudtrace.googleapis.com \
  logging.googleapis.com \
  cloudbuild.googleapis.com \
  --project ${PROJECT_ID}
API propagation
Newly enabled APIs may take up to 60 seconds to propagate. Wait a minute before proceeding.

Step 1 Create the Job Service Account

Create a dedicated service account for the Cloud Run Job. Do not reuse the connector's service account β€” the job SA requires write permissions that the connector SA should not have.

bash
gcloud iam service-accounts create ${JOB_SA_NAME} \
  --display-name="Vertex Tools Inventory Job" \
  --project=${PROJECT_ID}

echo "JOB_SA_EMAIL=${JOB_SA_EMAIL}"

Step 2 Grant IAM Roles

The job SA needs five project-level roles. Each covers a distinct collection responsibility:

RolePurpose
roles/dialogflow.viewerList agents, read webhooks (Dialogflow CX)
roles/aiplatform.viewerList reasoning engines (Vertex AI Agent Engine)
roles/iam.securityReviewerRead IAM policies for identity binding generation
roles/cloudtrace.userRead Cloud Trace spans for activity logs
roles/logging.viewerRead Cloud Logging for audit log collection
bash β€” grant all project-level roles
for role in \
  roles/dialogflow.viewer \
  roles/aiplatform.viewer \
  roles/iam.securityReviewer \
  roles/cloudtrace.user \
  roles/logging.viewer; do

  gcloud projects add-iam-policy-binding ${PROJECT_ID} \
    --member="serviceAccount:${JOB_SA_EMAIL}" \
    --role="$role" \
    --condition=None \
    --quiet
done
Idempotent
add-iam-policy-binding is a no-op if the binding already exists. Safe to re-run.

Step 3 Create the GCS Bucket

bash
gcloud storage buckets create gs://${BUCKET_NAME} \
  --location=${REGION} \
  --project=${PROJECT_ID} \
  --uniform-bucket-level-access
Bucket name conflict
GCS bucket names are globally unique. If ${BUCKET_NAME} is taken, use an alternate:
export BUCKET_NAME=vertex-inventory-${PROJECT_ID}

Grant the job SA write access

bash
gcloud storage buckets add-iam-policy-binding gs://${BUCKET_NAME} \
  --member="serviceAccount:${JOB_SA_EMAIL}" \
  --role="roles/storage.objectAdmin"

Step 4 Create the Artifact Registry Repository

bash
gcloud artifacts repositories create ${AR_REPO} \
  --repository-format=docker \
  --location=${REGION} \
  --project=${PROJECT_ID} \
  --description="Vertex Tools Inventory container images"

Step 5 Build & Push the Container Image

5a β€” Extract the deployment package

bash
tar xzf vertex-tools-inventory-deploy-1.0.tar.gz
cd vertex-tools-inventory

5b β€” Build via Cloud Build

Cloud Build reads the Dockerfile, builds the image, and pushes it to Artifact Registry. No local Docker build is required.

bash β€” ~2-5 minutes
# Configure docker auth for AR (one-time)
gcloud auth configure-docker ${REGION}-docker.pkg.dev --quiet

# Submit the build
gcloud builds submit . \
  --tag ${IMAGE} \
  --project ${PROJECT_ID} \
  --quiet
Verify the image
gcloud artifacts docker images list ${REGION}-docker.pkg.dev/${PROJECT_ID}/${AR_REPO} --include-tags

Step 6 Create the Cloud Run Job

The job configuration is passed entirely via the INVENTORY_CONFIG_JSON environment variable β€” no config file mount is needed.

bash
gcloud run jobs create ${JOB_NAME} \
  --image=${IMAGE} \
  --region=${REGION} \
  --project=${PROJECT_ID} \
  --service-account=${JOB_SA_EMAIL} \
  --set-env-vars="INVENTORY_CONFIG_JSON={\"flavor\":\"${FLAVOR}\",\"fixtures\":false,\"projectIds\":[\"${PROJECT_ID}\"],\"locations\":[\"${REGION}\"],\"output_dir\":\"/tmp/out\",\"bucketName\":\"${BUCKET_NAME}\",\"bucketPrefix\":\"vertex-inventory\",\"writeLatest\":true,\"activityLogEnabled\":true,\"activityLogWindowMinutes\":60}" \
  --task-timeout=600 \
  --max-retries=1 \
  --memory=512Mi
Updating an existing job
If the job already exists, replace create with update. The deploy.sh script in the deployment package handles this automatically.

Step 7 Create the Cloud Scheduler Trigger

7a β€” Grant the invoker role

bash
gcloud run jobs add-iam-policy-binding ${JOB_NAME} \
  --region=${REGION} \
  --member="serviceAccount:${JOB_SA_EMAIL}" \
  --role="roles/run.invoker"

7b β€” Create the schedule

bash β€” every 6 hours
gcloud scheduler jobs create http ${JOB_NAME}-scheduled \
  --location=${REGION} \
  --schedule="0 */6 * * *" \
  --uri="https://${REGION}-run.googleapis.com/apis/run.googleapis.com/v1/namespaces/${PROJECT_ID}/jobs/${JOB_NAME}:run" \
  --http-method=POST \
  --oauth-service-account-email=${JOB_SA_EMAIL} \
  --time-zone="UTC" \
  --project=${PROJECT_ID}

Recommended frequencies:

ScheduleCronUse Case
Hourly0 * * * *High-change environments
Every 6 hours0 */6 * * *Most deployments (recommended)
Daily0 6 * * *Stable environments

Step 8 Execute Manually & Verify

8a β€” Trigger a test execution

bash β€” 1-3 minutes
gcloud run jobs execute ${JOB_NAME} \
  --region=${REGION} \
  --wait
Execution failed?
Check job logs before proceeding: gcloud run jobs executions list --job=${JOB_NAME} --region=${REGION}. Common causes: missing IAM roles (re-check Step 2), APIs not enabled (re-check P2), or bucket doesn't exist (re-check Step 3).

8b β€” Verify GCS artifacts

bash
gcloud storage ls gs://${BUCKET_NAME}/vertex-inventory/latest/

Expected β€” six files:

activity-logs.json agents.json identity-bindings.json manifest.json service-accounts.json tool-credentials.json

8c β€” Inspect manifest.json

bash
gcloud storage cat gs://${BUCKET_NAME}/vertex-inventory/latest/manifest.json \
  | python3 -m json.tool
Confirm
agentCount, identityBindingCount, and serviceAccountCount are non-zero. generatedAt reflects the current timestamp. warnings contains only expected entries (group expansion warning is normal in v1).

8d β€” Inspect agents.json

bash
gcloud storage cat gs://${BUCKET_NAME}/vertex-inventory/latest/agents.json \
  | python3 -m json.tool | head -40

Confirm projectId matches ${PROJECT_ID}, flavor values match expected agent types, and resourceName paths are fully qualified.

8e β€” Inspect identity-bindings.json

bash
gcloud storage cat gs://${BUCKET_NAME}/vertex-inventory/latest/identity-bindings.json \
  | python3 -c "import json,sys; d=json.load(sys.stdin); print(f'{len(d)} bindings'); print(set(b['principalType'] for b in d))"

8f β€” Inspect activity-logs.json

bash
gcloud storage cat gs://${BUCKET_NAME}/vertex-inventory/latest/activity-logs.json \
  | python3 -c "import json,sys; d=json.load(sys.stdin); print(f'{len(d)} records'); print(set(r['event_type'] for r in d) if d else 'empty')"

If activity logs are empty and you expect agent activity, check the manifest activityLogWarnings for diagnostic messages (e.g. NO_TRACE_TELEMETRY means agent telemetry is not enabled).

Updating the Image

After receiving an updated deployment package:

bash β€” rebuild, push, update job
# Extract updated package
tar xzf vertex-tools-inventory-deploy-1.1.tar.gz
cd vertex-tools-inventory

# Build and push
gcloud builds submit . \
  --tag ${IMAGE} \
  --project ${PROJECT_ID} \
  --quiet

# Update the Cloud Run Job to use the new image
gcloud run jobs update ${JOB_NAME} \
  --image=${IMAGE} \
  --region=${REGION} \
  --project=${PROJECT_ID}

# Execute to verify
gcloud run jobs execute ${JOB_NAME} \
  --region=${REGION} \
  --wait

Teardown

The deployment package includes a teardown.sh script that removes all resources in reverse order with confirmation prompts. To run non-interactively:

bash
# Interactive (confirms each resource)
./teardown.sh

# Non-interactive
./teardown.sh --force

Resource Summary

ResourceVariable / Name
Cloud Run Job${JOB_NAME} β€” vertex-tools-inventory
Job Service Account${JOB_SA_EMAIL} β€” vertex-inventory-job@…
Inventory GCS Bucket${BUCKET_NAME} β€” ${PROJECT_ID}-vertex-inventory
Artifact Registry Repo${AR_REPO} β€” vertex-inventory
Container Image${IMAGE} β€” ${REGION}-docker.pkg.dev/…
Cloud Scheduler${JOB_NAME}-scheduled
ScheduleEvery 6 hours (0 */6 * * *)
RuntimePython 3.12 (container)
Task timeout600s
Memory512 Mi
Max retries1