-
Notifications
You must be signed in to change notification settings - Fork 0
Drift Detection
The Drift Detection module compares the live, effective configuration of two configured GCP environments in one read-only call. Ask for a whole-environment comparison, or narrow the request to one or more components such as Cloud Run, GKE, networking, Pub/Sub, or BigQuery.
The comparison is symmetric. Neither environment is treated as a baseline, target, source of truth, or desired state. Results always use the configured aliases:
- A resource present in
prodbut absent fromdevis Missing in dev and Only in prod. - A resource present in
devbut absent fromprodis Missing in prod and Only in dev. - A matched resource with different effective settings is Changed, with values labeled
devandprod.
This makes the output safe to read in either order. “Compare prod and dev” does not silently assign special meaning to the first or second environment.
Drift detection requires at least two configured environments. For local use, add them to ~/.aura-tracker.yaml:
environments:
- project_id: my-company-dev
alias: dev
default: true
- project_id: my-company-prod
alias: prodStart only the drift tool:
./aura-tracker-gcp --modules driftFor a container or hosted deployment, use the equivalent JSON setting:
GCP_ENVIRONMENTS_JSON='[{"project_id":"my-company-dev","alias":"dev","default":true},{"project_id":"my-company-prod","alias":"prod"}]' \
./aura-tracker-gcp --modules driftBoth selectors are mandatory for a comparison; the default environment is not silently substituted for either side. Aliases are case-insensitive, and configured project IDs are accepted as input, but responses use aliases and do not expose aliased project IDs.
See Configure Your Environment for all validation and privacy rules.
“Find drifts between dev and prod.”
“What is different between project 111 and project 222?”
When no component is named, components is omitted and all supported components are compared.
“Find diffs between prod Cloud Run and dev Cloud Run.”
“What is the difference between dev GKE setup and prod GKE setup?”
“Compare networking and Pub/Sub in dev and prod.”
“Compare Cloud Run, Cloud SQL, and Scheduler between staging and prod. Show detailed field differences.”
“Compare the
apiservice in dev and prod Cloud Run.”
“Compare GKE workloads in the
paymentsnamespace between dev and prod.”
The MCP server instructions route drift, diff, difference, parity, and two-environment comparison requests to gcp_compare_environments. The final answer is presented as a summary, alias-named missing-resource sections, changed fields with values from both aliases, and coverage gaps last.
| Component value | Compared resources and configuration |
|---|---|
bigquery |
Datasets, tables, partition fields, labels, and bounded table schemas |
cloudrun |
Services, jobs, traffic, ingress, scaling, security settings, and the selected revision template |
cloudsql |
Instances, database version, region, tier, and labels; advanced settings are reported as a coverage limitation |
datastores |
Spanner, AlloyDB, Firestore, and Memorystore inventory and exposed configuration |
eventarc |
Triggers, destinations, transport topics, filters, service accounts, and labels |
functions |
Gen 1 and Gen 2 functions, runtime, entry point, memory, timeout, identity, VPC connector, and labels |
gke |
Clusters, node pools, versions, networking, identity, private-cluster and security settings, autoscaling, and add-ons |
gke_workloads |
Workloads, container specs, Services, Ingress/HTTPRoute resources, and NetworkPolicies across discovered clusters |
iam |
Service-account inventory and configuration; project and resource bindings are explicitly reported as not covered |
monitoring |
Alert policies, uptime checks, SLOs, and dashboards |
networking |
Load balancers, URL maps, NEGs, API Gateways, VPC networks, subnets, and PSC endpoints |
pubsub |
Topics, labels, subscriptions, destinations, dead-letter topics, and filters |
scheduler |
Jobs, schedules, time zones, target kinds, target references, and descriptions |
secretmanager |
Secret names, labels, and replication mode; secret payloads are never read |
storage |
Buckets, location/class, labels, versioning, uniform access, public-access prevention, and lifecycle-rule counts |
supplychain |
Artifact Registry repositories, Cloud Build triggers, and Service Directory namespaces |
tasks |
Queue presence; current rate and retry settings are reported as a coverage limitation |
vpcaccess |
Serverless VPC Access connectors and networks |
workflows |
Workflow presence, descriptions, and labels |
“Whole environment” means every component in this supported comparison surface. It does not imply that every GCP product or every field in every Google API is collected. Known limitations are returned in coverage and warnings rather than hidden.
Compares two distinct configured environments.
| Parameter | Required | Default | Description |
|---|---|---|---|
environment_a |
yes | — | First configured alias or project ID; positional only, not authoritative |
environment_b |
yes | — | Second configured alias or project ID; must resolve to a different environment |
components |
no | all supported | One or more component values from the table above |
resource_names |
no | all | Exact resource names to include, up to 100 |
locations |
no | all | Regions or zones to include, up to 100 |
namespaces |
no | all | Kubernetes namespaces when comparing gke_workloads, up to 100 |
detail_level |
no | standard |
summary, standard, or detailed
|
include_unchanged |
no | false |
Include matched resources whose normalized configuration is equivalent |
max_changes |
no | 250 |
Maximum resource results returned, from 1 to 1000 |
The tool is read-only, side-effect-free, and bounded by a 90-second comparison budget. Collection runs with bounded concurrency, and each component is capped at 500 collected resources per environment. If a cap or timeout is reached, coverage becomes partial.
Whole environment:
{
"environment_a": "dev",
"environment_b": "prod"
}Selected components and a resource filter:
{
"environment_a": "dev",
"environment_b": "prod",
"components": ["cloudrun", "gke"],
"resource_names": ["api"],
"detail_level": "detailed"
}The response separates the comparison result from collection coverage.
result |
Meaning |
|---|---|
differences_found |
At least one matched resource changed, or a resource was conclusively found in only one environment |
parity |
At least one resource was compared, no differences were found, and coverage was complete |
no_differences_observed |
Comparable resources matched, but partial coverage prevents a full parity claim |
no_comparable_resources |
No resource pair could be compared, commonly because both scopes were empty or one side failed collection |
status |
Meaning |
|---|---|
different |
Both resources were matched, but normalized configuration differs |
missing_in_environment |
Resource presence was checked completely; missing_in contains the exact alias |
equivalent |
Matched configuration is equivalent; returned only when include_unchanged=true
|
unknown_due_to_coverage |
A resource was observed on only one side, but incomplete collection prevents a missing-resource claim |
summary.resources_only_in is alias-named rather than side-oriented:
{
"resources_only_in": [
{"environment": "dev", "resources": 2},
{"environment": "prod", "resources": 1}
]
}A changed field carries values from both environments:
{
"path": "/revision_template/min_instances",
"change_type": "modified",
"category": "scaling",
"importance": "medium",
"values_by_environment": [
{"environment": "dev", "value": 0, "present": true},
{"environment": "prod", "value": 3, "present": true}
]
}The summary detail level omits the full resource list and keeps up to three field differences per highlight. standard keeps up to ten field differences per resource. detailed returns every collected field difference, subject to max_changes and collection limits.
Resources are matched deterministically by resource type and logical name. Location and qualifiers—such as dataset, cluster, namespace, or Kubernetes kind—disambiguate repeated names. A uniquely named resource can still be matched when its location changes, allowing the location difference to be reported as configuration drift.
Before comparison, the engine:
- replaces environment-local project IDs with a neutral
${PROJECT}marker; - removes operational fields such as timestamps, readiness, status, generated endpoints, etags, and generated revision identities;
- normalizes unordered arrays and aligns named objects before producing field paths;
- preserves ordered command and argument arrays;
- compares the current Cloud Run revision through a project-normalized safe fingerprint, detecting literal environment-value changes without returning those values;
- compares arbitrary GKE annotation changes through sorted, private one-way fingerprints even when the number of withheld annotations is unchanged;
- sorts resources, fields, coverage, and warnings for stable output.
The v2 normalizer also applies defense-in-depth output sanitization after comparison. Sensitive path variants and containers—credentials, tokens, authorization, cookies, signatures, DSNs, connection strings, private keys, secret-bearing annotations, and environment literal fingerprints—are replaced with [REDACTED]. URL/URI/endpoint fields preserve useful routing structure while removing userinfo and fragments and replacing every query value. Diagnostic warnings and coverage errors are scrubbed for embedded credentials, JWTs, private keys, and credential-bearing URLs.
Normalization prevents expected deployment noise from overwhelming the answer while retaining meaningful scaling, security, networking, runtime, and application-configuration differences.
Coverage is recorded independently for every component and alias as complete, partial, or error.
An API error is never converted into an empty environment. When either side is partial, an unmatched resource is labeled unknown_due_to_coverage; the tool does not claim it is missing. This distinction is particularly important for:
- GKE clusters that are private, unreachable, or denied by Kubernetes RBAC;
- regional APIs where only some regions can be listed;
- truncated BigQuery schemas or component resource caps;
- IAM, Cloud SQL, and Cloud Tasks fields not exposed by the current collectors;
- timeouts and permission failures.
The top-level coverage_status is partial when any requested component has a gap. Review coverage and warnings before treating an absence as proof.
- The tool never mutates either environment.
- Secret Manager payloads are never requested.
- Cloud Run literal environment values contribute only to a one-way configuration fingerprint.
- GKE literal environment-variable values are compared in memory but replaced with
[REDACTED]in reported differences. - Arbitrary GKE annotation values and their fingerprints never serialize; fingerprint differences are replaced with
[REDACTED]. - Sensitive field names and semantic-array identity values are also removed from public JSON-pointer paths, preventing a secret from leaking through a difference path or summary rather than its value.
- Secret references are represented by names, never secret payloads.
- Configured project IDs are replaced by aliases in results, errors, coverage messages, and summaries.
- The regular anonymization middleware still runs after drift comparison when
ANONYMIZE_ENABLED=true.
Drift detection reuses the existing read-only collectors. Enable the APIs and grant the viewer roles required by every component you intend to compare. The same server identity must have those permissions in both projects.
For example:
| Compared scope | Relevant module documentation |
|---|---|
| Cloud Run | Cloud Run |
| GKE clusters and workloads | GKE, GKE Workloads |
| Networking | Networking, Serverless VPC Access |
| Pub/Sub and eventing | [[Pub/Sub |
| BigQuery metadata and schemas | [[MCP Resources Reference |
| Data and storage | Cloud SQL, Data Stores, Cloud Storage |
| IAM and secrets | IAM, Secret Manager |
| Monitoring | Cloud Monitoring and Trace |
| Supply chain | Supply Chain |
Run the idempotent setup once per real project ID, not per alias:
PROJECT_ID=my-company-dev bash scripts/setup-iam.sh
PROJECT_ID=my-company-prod bash scripts/setup-iam.shFor GKE workload comparison, the identity also needs Kubernetes read-only RBAC in each cluster. Inaccessible clusters appear as coverage gaps.
| Module | How it complements drift detection |
|---|---|
archgraph |
Visualize the live topology around resources that differ |
security |
Run a deeper security-posture assessment after security-relevant drift is found |
incident |
Correlate runtime evidence when a configuration difference may explain an outage |
tagging |
Check governance tags that are outside the current drift collection surface |
cost |
Investigate whether changed capacity or traffic also changed spend |
Documentation for aura-tracker-gcp · Found a documentation issue? Open an issue
Aura Tracker GCP
Safety and operations
- Safety & Cost Safeguards
- Security & Safety
- Project Security Posture
- Incident Diagnosis
- Drift Detection
- Managing GCP Costs
- Cost Reasoning
Architecture and observability
- Architecture Graph
- Automatic Architecture Diagrams
- Serverless Graph
- Service Topology
- Observability Coverage
- Cloud Monitoring & Trace
- Cloud Logging
- Aura Score
Compute and networking
Data, messaging, and delivery
- Cloud SQL
- Cloud Storage
- Data Stores
- Secret Manager
- Pub/Sub
- Eventarc
- Cloud Scheduler
- Cloud Tasks
- Cloud Workflows
- Supply Chain
- Resource Tagging
- IAM
Reference