CloudPanorama Request evaluation

Capabilities

What the self-hosted build does and does not do: each capability's status, every module that runs with the IAM actions it makes, what is never read, and the versions it is tested on.

The capability matrix for the invitation-only self-hosted build: what ships, what is still in development, what is planned, and what is deliberately never done. The statuses use the public site's three words:

  • available now — implemented and test-backed in the build. That is not a claim that a pilot has validated it.
  • in development — implemented or partly implemented, with live verification or a production dependency still open.
  • planned — a direction with no delivery date. It is not in the build.

Two tests in observability/internal/cli hold this page to the code. TestTheCapabilityMatrixNamesWhatRuns checks that every module the scheduler runs has a row here, that no row names a module it does not run, and that every IAM action a collector makes is listed beside it. TestTheCapabilityMatrixMatchesTheRolesGrants checks each role's section against its CloudFormation template, in both directions: every action the template grants is listed there, and nothing listed there is ungranted.

Scope

  • Cloud: AWS, and Google Cloud projects in Estate (Compute Engine instances, GKE clusters, Cloud SQL instances, Cloud Storage buckets, VPC networks and subnets, load balancers, Cloud Run services, Pub/Sub topics and subscriptions, BigQuery datasets, service accounts, Firebase apps and Cloud Functions, read through workload identity federation), and Google Cloud billing in Spend: a billing account's BigQuery export, read daily. Azure subscriptions in Estate: the platform signs in and collects virtual machines, AKS clusters, SQL databases, PostgreSQL flexible servers, storage accounts, virtual networks and App Service apps, and Admin → Accounts connects a subscription; every collector and the reader role's exact reads were verified against a live test subscription. Azure spend in Spend: a subscription's Cost Management export, read daily. Azure provisioning through the library's templates, each run live on a test subscription. Import's generated template for an Azure resource and Azure templates of your own and Blueprints with Azure slots are in development.
  • Deployment: self-hosted, with Docker Compose or the Kubernetes kustomizations in deploy/. A hosted service is planned, after the first self-hosted pilot.
  • Licence: offline, verified by the binary alone. The tiers are Essentials (Estate), Professional (Estate and Spend) and Enterprise (Estate, Spend and Provisioning, and the enterprise capabilities). Performance comes with Professional and Enterprise.
  • Validation on a live account: one AWS account, the platform's own, was onboarded, collected, alerted on and billed end to end. That covers the external id's negative check, a status change delivered to a webhook, and a delivered Cost & Usage Report reconciled against Cost Explorer. A test estate was brought up and torn down through the product's own Provisioning templates, the agent applying them against that account as the reader role. Validation across separate customer accounts is in development.

Capabilities

Module Capability Status
Estate Inventory, derived health and the permanent status history available now
Estate The Dashboard: what needs someone now, ranked, each item linked to the page that explains it, then the estate by cloud and category, collection, spend against forecast, provisioning, recent changes and the hottest resources — the first page after sign-in available now
Estate Alerts, Slack and webhook notifications, and a public status page without identifiers — the front door for a visitor with no session available now
Estate Microsoft Teams, PagerDuty and email channels, each tested against a stand-in, email also against a real mail server; delivery to a live PagerDuty service and through a live mail relay is proven by the operator, with a step in the operator's manual available now
Estate Acknowledgeable alerts: a member acknowledges with a required note; the alert leaves the list until the resource changes again, and the acknowledgement is on the timeline available now
Estate Tag-defined application groups and declared apps, and freshness by each module's cadence available now
Estate Configuration diffs between snapshots on every resource's page, sensitive fields suppressed available now
Estate The change feed: configuration diffs, status transitions, acknowledgements, provisioning outcomes, cost anomalies and budget thresholds in one timeline per resource, account, app and team, ordered by the event's own time, with markers the customer's own systems post under a marker credential available now
Estate Ownership: one resolver deciding every resource's owning team from overrides, provenance, tags, the account and its relationships, with confidence and evidence, on every page that names an owner available now
Estate Impact and the investigator: one change and what moved around it — status, performance and settled cost on the resource and its neighbours — and, for a symptom, the changes before it ranked by time, distance and kind, each a candidate and never called a cause available now
Estate Tag policy: the tag keys a resource must carry and the values each admits, who complies with the money beside each answer, and at creation the agent stamps the team key, a request the policy cannot satisfy refused before it exists available now
Estate Findings: what needs fixing, grouped and prioritised, each priority showing its parts and its evidence available now
Estate Change alerts: a subscription to configuration changes that match a small predicate, judged as each read arrives, for a team or a declared app available now
Estate Relationships: a resource's neighbours — what contains it, what runs on it, what fronts and guards it, what provisioned it, the apps it belongs to, the team that owns it — each with evidence and confidence, drawn on its page available now
Estate Performance: latency, errors and saturation from CloudWatch with statistics, interactive charts and topology diagrams; EKS in depth, from the control plane to each pod available now
Estate Performance in depth: maxima, p95 and p99, a 30-day window read from an hourly rollup, and the hottest resources per signal with their pressure and a sparkline available now
Estate Performance for Google Cloud projects, from Cloud Monitoring: Compute Engine instances, Cloud SQL instances, Cloud Storage buckets, Application Load Balancers' forwarding rules, Cloud Run services, Pub/Sub topics and subscriptions, with the same statistics, windows and charts available now
Estate Performance for Azure subscriptions, from Azure Monitor: virtual machines, PostgreSQL flexible servers, SQL databases, storage accounts, App Service apps and AKS clusters, with the same statistics, windows and charts available now
Estate The inventory read every ten minutes, and the EC2 instances that start and stop between two reads recorded from EC2's own state-change events, with each run's start, end and lifetime in Changes available now
Estate Who made a configuration change: the CloudTrail events that may be it — principal, call and time, each a candidate and none chosen — on the change in Changes and in the investigator's evidence, for an AWS account whose administrator turns CloudTrail attribution on, within CloudTrail's 90 days available now
Estate Accounts: every connected AWS account, Google Cloud project and Azure subscription as an overview — what it holds by status and region, the state of its collection, the worst and stalest collector and when it was last read successfully — for any signed-in member available now
Estate Google Cloud projects: Compute Engine instances, GKE clusters, Cloud SQL instances, Cloud Storage buckets, VPC networks and subnets, Cloud Run services, Pub/Sub topics and subscriptions, BigQuery datasets, service accounts, Firebase apps and Cloud Functions, read through workload identity federation with a metadata-only custom role, every request field-masked available now
Estate Cloud Functions read from the Functions API's masked listing: every function under its own name whether or not it has run, with its state and labels, gone when the listing stops naming it available now
Estate Azure subscriptions: virtual machines, AKS clusters, SQL databases, PostgreSQL flexible servers, storage accounts, virtual networks and App Service apps, read by an app with no secret through federation and a custom role with no data action, connected from Admin → Accounts; every collector, and the role's refusal of content reads, verified against a live test subscription available now
Spend Cost Explorer ingestion with a 12-month backfill; Cost & Usage Report ingestion and amortization available now
Spend Tag allocation rules, inventory exceptions, anomalies, team budgets and Trusted Advisor recommendations available now
Spend Kubernetes attribution by the pods and nodes last seen, a current-placement approximation stated beside the figures available now
Spend Month-end forecasts with their range and measured error, on the tenant, team and account pages available now
Spend Reconciliation: a month's total from the places that must agree, per currency, with coverage and charge type beside it in development
Spend Cost change explanation: what moved between two periods, the movers summing to the difference, the changes in the same window beside them and never called causes available now
Spend Savings verification: a recommendation's saving split into usage and rate from the report's own quantities available now
Spend Showback out of the product: a page's table as CSV and a weekly digest per team by email in development
Spend Azure spend: a subscription's Cost Management export — FOCUS, or the ActualCost and AmortizedCost pair — read daily from its one storage container, as the subscription's reader, into the same cost tables, each export configured on Spend's Settings page with its last read available now
Spend Google Cloud billing: a billing account's detailed usage cost export in BigQuery, read daily by the project holding it into the same cost tables, under the same authority rule, with labels attributed as tags, each cloud in its own currencies on the overview; Google's figures are its cost before credits, or after committed-use credits alone, and the Overview says which; its figures are in the same anomalies, team budgets and month-end forecasts as AWS's available now
Provisioning Versioned templates, typed inputs, approvals, provenance tags, drift detection and scrubbed execution logs available now
Provisioning The customer-run agent: a broker that holds the token and a worker that runs OpenTofu under another user available now
Provisioning An OpenTofu apply against a live AWS account: the test estate brought up and torn down through the product's own templates available now
Provisioning The library: built-in OpenTofu templates for the AWS types the inventory reads, checked by hash in the agent, enabled for the organisation, cloned to edit, with a notice when a newer release arrives available now
Provisioning Each library release runs the small Blueprint — a network, a database and a service — live in a test account, from request to destroy available now
Provisioning A role per template on AWS: with the setting on, each request runs as its template's own role, granted only that template's documented policy and the state bucket; a missing role fails the request, never falling back to the agent's identity available now
Provisioning The catalog: category, then type, then template, with the accounts whose agent can run each available now
Provisioning Blueprints: several templates requested as one run across slots of accounts, one approval bound to the run's expressions, each step a request, resume after a failure and destroy in reverse available now
Provisioning Import: a live resource recorded under a template version that declares its type and a team, with its provenance, its owner and its history; nothing is written to the cloud, and drift is not computed until it is fully managed available now
Provisioning The agent on Google Cloud: an agent token for a project, Google provenance labels and state in a Cloud Storage bucket available now
Provisioning An agent installed in one step for an AWS account the platform already reads, through a CloudFormation quick-create link available now
Provisioning Making an import fully managed: an import-only apply into the agent's state, then a separately approved retag, and release from state available now
Provisioning Import of a resource no template in the catalog declares, on AWS and Google Cloud: the account's agent generates its template, kept as a private version outside the catalog, and runs it as that resource type's own runner available now
Provisioning Google Cloud templates in the library: storage, messaging, networking, identity, compute and clusters, serverless and databases available now
Provisioning Azure templates in the library — a private storage account and one for archives, a virtual network with private subnets and one behind a NAT gateway, a private Linux virtual machine and a Spot one, a function app for background work and one for HTTPS callers in named address ranges, a PostgreSQL flexible server for development and a highly available one, a serverless SQL database for development and a zone-redundant one, a private AKS cluster and one answering named networks — each in an existing resource group, each run as its own managed identity with a token of its own, holding only its template's actions, in the subscription the request is for, with OpenTofu state in a storage container of the customer's; each run live through the product on a test subscription available now
Provisioning Import's generated template for every Azure type Estate collects in development
Provisioning Azure templates of your own, from git or inline, and Blueprints with Azure slots: a request runs on an agent whose runners are scoped to resource groups, and waits, naming the setting, until the account's agent is; an inline source is checked at publish for what the agent refuses — its own sign-in, a renamed provider, provider registration, a resource group made, OpenTofu state read in development
Provisioning Blueprints in the library: a network, a database and a service; Kubernetes with an Istio mesh across clusters available now
Provisioning A service account per template on Google Cloud, impersonated by the agent, its custom role only the template's documented policy and its own part of the state bucket available now
Provisioning Runners for templates of your own: the AWS, Google Cloud and Azure runners modules make one per template, scoped as the library's are, and a template of yours never runs as a library runner available now
Provisioning Stopping an EC2 instance through an approved request, from its resource page, verified by the next complete collection available now
Provisioning An expiry on a request that opens its destroy request planned
Provisioning In-place updates of a provisioned stack not in v1
Platform Users, roles and teams; sessions with a per-user cap; step-up for destructive administrator actions; the audit trail available now
Platform Connecting an account from the portal: register an AWS account, a Google Cloud project or an Azure subscription, with the template and the exact commands to run in the customer's cloud (an AWS account's with its external id), verification before it is enabled, collection paused and resumed, one collection now, and removal — the CLI is needed for none of it available now
Platform The Admin area — the organisation, the audit log and an overview of the licence, the people and the accounts — and each user's own settings: profile, sessions, notifications, preferences available now
Platform Team scope: a member sees the spend, the anomalies, budgets and forecasts, the change feed and the provisioning requests of their own teams' accounts, and no other team's; the inventory and its status history are every member's (PLATFORM.md §4) available now
Platform First run: a checklist from connecting an account to the first request, a guided tour over the real pages, and a Help menu available now
Platform Backups and a restore that does not replay cloud changes (the runbook, "Backing up and restoring the database") available now
Platform Single sign-on through the organisation's OpenID Connect provider (Entra ID, Okta, Google, IAM Identity Center), beside passwords or enforced with break-glass administrators; with the Enterprise licence's sso capability available now
Platform Directory group sync: teams bound to the provider's groups, membership following the directory available now
Platform One home identity: with more than one cloud, the platform signs in at one and the others federate from it, with AWS or Google Cloud as the home available now
Platform Azure as the home identity in development
Platform SAML single sign-on and SCIM provisioning planned
Platform The AI reviewer channel: alerts and cost anomalies handed to an operator's own reviewer as claim checks, its answer on the subject and in the inbox, with evidence the tenant can see; sent from the page that asked available now
Platform The reviewer service itself, run by the operator, with a local model first (the owner, 2026-10-08) available now
Platform Triage: a small model the operator runs beside the platform decides for each status change, cost anomaly, budget, provisioning event, change and finding whether it needs people, the AI reviewer or nobody; shadow first, routing unchanged, every decision recorded with its confidence and its agreement with what people did, per kind in Admin available now
Platform Triage routing events by its decision, within floors and thresholds, once a kind is switched to enforce in development
Platform Usage that departs from a resource's own history, raised as an event for Triage available now
Platform Read-only API tokens for the API's GET routes available now
Platform The operator's manual, served to administrators inside the product available now

The reader role

deploy/cloudformation/reader-role.yaml, deployed in every connected account. It grants exactly the actions in the three lists below, and no wildcard. None of them returns S3 object contents, log events, CloudFront configurations or Lambda source, each of which can hold a customer's data or credentials. One returns the metadata of API calls: cloudtrail:LookupEvents, CloudTrail's event history — who called what, on which resource, and when — read for the one resource that changed, between its two observations, and only for an account whose administrator turned CloudTrail attribution on (the owner, 2026-10-07). Of an event the platform keeps its id, name, time and principal, never its request, its response or its source address, and it reads no Lake query, trail bucket or data event. The template lists the reasons, and its test holds the allowlist. Its trust policy lets the platform assume it with the account's external id (sts:AssumeRole), set its source identity (sts:SetSourceIdentity) and tag its session (sts:TagSession).

Called by the inventory collectors

Most run per account and region. S3's and CloudFront's resources have a global identity, so those two run once per account. CloudFront's distributions and Lambda's functions are found from the metrics each publishes, not from their configuration, which carries the origins' custom headers and the functions' environment variables.

Module Resource Tier IAM actions
aws.ec2.instance EC2 instances standard ec2:DescribeInstances, ec2:DescribeInstanceStatus
k8s.eks.workload Kubernetes workloads on EKS standard eks:ListClusters, eks:DescribeCluster
aws.eks.cluster EKS clusters standard eks:ListClusters, eks:DescribeCluster, eks:ListNodegroups, eks:DescribeNodegroup
aws.rds.instance RDS instances standard rds:DescribeDBInstances
aws.s3.bucket S3 buckets, per account slow s3:ListAllMyBuckets, s3:GetAccountPublicAccessBlock, s3:GetBucketTagging, s3:GetBucketVersioning, s3:GetEncryptionConfiguration, s3:GetBucketPublicAccessBlock, s3:GetBucketPolicyStatus, s3:GetMetricsConfiguration
aws.dynamodb.table DynamoDB tables standard dynamodb:ListTables, dynamodb:DescribeTable, dynamodb:DescribeContinuousBackups, dynamodb:ListTagsOfResource
aws.elb.loadbalancer Load balancers and their targets standard elasticloadbalancing:DescribeLoadBalancers, elasticloadbalancing:DescribeTargetGroups, elasticloadbalancing:DescribeTargetHealth, elasticloadbalancing:DescribeTags
aws.sqs.queue SQS queues standard sqs:ListQueues, sqs:GetQueueAttributes, sqs:ListQueueTags
aws.sns.topic SNS topics standard sns:ListTopics, sns:GetTopicAttributes, sns:ListSubscriptionsByTopic, sns:ListTagsForResource
aws.apigateway.api API Gateway APIs standard apigateway:GET
aws.backup.vault AWS Backup vaults standard backup:ListBackupVaults, backup:ListTags
aws.acm.certificate ACM certificates standard acm:ListCertificates, acm:DescribeCertificate, acm:ListTagsForCertificate
aws.ec2.natgateway NAT gateways standard ec2:DescribeNatGateways
aws.cloudfront.distribution CloudFront distributions with traffic in the last two weeks, per account, by id; their status unknown standard cloudwatch:ListMetrics
aws.kinesis.stream Kinesis data streams standard kinesis:ListStreams, kinesis:DescribeStreamSummary, kinesis:ListTagsForStream
aws.lambda.function Lambda functions invoked in the last two weeks, by name; their status unknown standard cloudwatch:ListMetrics
aws.elasticache.cluster ElastiCache clusters standard elasticache:DescribeCacheClusters, elasticache:ListTagsForResource
aws.opensearch.domain OpenSearch Service domains, by name and engine; their status unknown standard es:ListDomainNames, es:ListTags
aws.glue.job Glue jobs, by name; their status unknown standard glue:ListJobs, glue:GetTags
aws.athena.workgroup Athena workgroups standard athena:ListWorkGroups, athena:ListTagsForResource
aws.ec2.volume EBS volumes and their status checks standard ec2:DescribeVolumes, ec2:DescribeVolumeStatus
aws.ec2.vpc VPCs standard ec2:DescribeVpcs
aws.ec2.subnet Subnets standard ec2:DescribeSubnets
aws.ec2.securitygroup Security groups, their rules counted standard ec2:DescribeSecurityGroups
aws.ec2.elastic-ip Elastic IP addresses standard ec2:DescribeAddresses
aws.ec2.vpcpeering VPC peering connections standard ec2:DescribeVpcPeeringConnections

Called by the other jobs and by onboarding

Caller IAM actions
cost.ce_aggregate, cost.ce_resource, cost.ce_backfill ce:GetCostAndUsage, ce:GetCostAndUsageWithResources
cost.azure_billing Azure's Cost Management export, the current and the previous month
cost.trusted_advisor support:DescribeTrustedAdvisorChecks, support:DescribeTrustedAdvisorCheckResult (it needs a support plan that includes Trusted Advisor)
perf.cloudwatch, perf.cloudwatch.global cloudwatch:GetMetricData, cloudwatch:ListMetrics
aws.ec2.lifecycle sqs:ReceiveMessage, sqs:DeleteMessage, on the reader role's own queue, <RoleName>-ec2-lifecycle, alone, never on any other queue
aws.cloudtrail.attribution, for an account with CloudTrail attribution on cloudtrail:LookupEvents, one page of at most 50 events per configuration change, at most twice a second per account and region
Onboarding a management account, to read its members organizations:ListAccounts, organizations:DescribeOrganization

Granted ahead of a collector

These were granted when the template was written, for the EC2 collectors still to come: instance types, security group rules, network interfaces, route tables, gateways, endpoints, regions and zones. Each was reviewed as metadata-only. Nothing calls them yet. A collector that starts calling one moves it into its own list, as the NAT gateway collector did and the volume, VPC, subnet, security group and Elastic IP collectors did and the VPC peering collector did, and one that nobody ever calls is removed from the template.

ec2:DescribeInstanceTypes, ec2:DescribeSecurityGroupRules, ec2:DescribeNetworkInterfaces, ec2:DescribeRouteTables, ec2:DescribeInternetGateways, ec2:DescribeVpcEndpoints, ec2:DescribeTags, ec2:DescribeRegions, ec2:DescribeAvailabilityZones

The Google Cloud reader

deploy/gcp/reader-role.yaml, a custom role in each connected Google Cloud project, bound to the project's reader service account. The platform signs in by workload identity federation from its own AWS identity and impersonates that account; no key file exists. The role grants exactly the permissions below. No predefined viewer role would do: each reads content somewhere, Datastore entities, a routine's body, a function's environment, a service account's keys, or the project's shared instance metadata. Cloud Functions are read from the Functions API's listing, masked, never its get. Verification also reads the reader account and the project (iam.serviceAccounts.get, resourcemanager.projects.get).

Module Resource Tier Google permissions
gcp.bigquery.dataset BigQuery datasets, per project; never a table, schema, routine or row standard bigquery.datasets.get
gcp.iam.serviceaccount Service accounts, per project; never their keys standard iam.serviceAccounts.list
gcp.firebase.app Firebase apps, per project; never their configuration standard firebase.clients.list, firebase.projects.get
gcp.functions.function Cloud Functions, per project, by their own name, whether or not they have run: state, labels and times; their triggers from the last two weeks' execution counts; never their environment, secrets, build or trigger configuration standard cloudfunctions.functions.list, monitoring.timeSeries.list
gcp.compute.instance Compute Engine instances, per region, zone by zone; never their metadata standard compute.regions.get, compute.instances.list
gcp.container.cluster GKE clusters and their node pools, per region, at the region and each zone; never their credentials or node configuration standard compute.regions.get, container.clusters.list
gcp.sqladmin.instance Cloud SQL instances, per project, their region a property standard cloudsql.instances.list
gcp.storage.bucket Cloud Storage buckets, per project, their location a property; never an object or an access list standard storage.buckets.list
gcp.compute.network VPC networks, per project: mode, routing, the regions their subnets are in, peerings and their state standard compute.networks.list
gcp.compute.subnetwork VPC subnets, per region: ranges, purpose, private access, flow logs standard compute.subnetworks.list
gcp.run.service Cloud Run services, per region, second-generation Cloud Functions among them; never a container's environment, arguments or command, or a build's configuration standard run.services.list
gcp.pubsub.topic Pub/Sub topics, per project; never a message or a message transform standard pubsub.topics.list
gcp.pubsub.subscription Pub/Sub subscriptions, per project; never a message, a push endpoint or a message transform standard pubsub.subscriptions.list
gcp.compute.forwardingrule Load balancers: a region's forwarding rules, each with the chain behind it (target proxy, URL map, backend services) and its backends' health; never a header value a backend service or a URL map carries standard compute.forwardingRules.list, compute.regionTargetHttpProxies.list, compute.regionTargetHttpsProxies.list, compute.regionTargetTcpProxies.list, compute.regionUrlMaps.list, compute.regionBackendServices.list, compute.regionBackendServices.get
gcp.compute.globalforwardingrule Load balancers: the project's global forwarding rules, each with the chain behind it and its backends' health; never a header value a backend service or a URL map carries standard compute.globalForwardingRules.list, compute.targetHttpProxies.list, compute.targetHttpsProxies.list, compute.targetGrpcProxies.list, compute.targetSslProxies.list, compute.targetTcpProxies.list, compute.urlMaps.list, compute.backendServices.list, compute.backendServices.get

A load balancer's backend health is read with backendServices.getHealth, a POST that reads and changes nothing; it needs the backend service's get permission. It is the only POST the platform makes to Google Cloud, and the platform refuses any other before it is sent.

Twelve permissions allow more than the product reads. compute.instances.list returns each instance's metadata items (startup scripts, SSH keys, any value an operator stored there); container.clusters.list returns each cluster's master credentials and its nodes' metadata; run.services.list returns each Cloud Run service's containers' environment variables and their values, arguments and commands, and its build's configuration; pubsub.topics.list returns each topic's message transforms, which are JavaScript source; pubsub.subscriptions.list returns the same transforms and each push subscription's endpoint, a URL that may carry a credential; compute.backendServices.list and compute.regionBackendServices.list, and the get permissions beside them, return each backend service's custom request and response headers, whose values may carry a credential, the identifier of an AWS access key it signs with, and its IAP client and that client's secret's hash; compute.urlMaps.list and compute.regionUrlMaps.list return the header values a URL map's routes add and match; and cloudfunctions.functions.list returns each function's build and service configuration, its environment variables and their values and its secret references among them, and its event trigger. None of them can be granted without those fields. Every request the platform makes carries a partial-response field mask (fields=) that names only the metadata it shows, so the content never crosses the wire, and an answer that carries it anyway is refused whole and nothing of it is stored (MILESTONE_1 §13.3). The mask is enforced by the platform's code and its tests; the role itself would let the reader see the content.

Regions. Instances, clusters, subnets, Cloud Run services and regional load balancers are read one region at a time, in the regions the project uses; global load balancers once per project. A project registers with none; region discovery finds them and adds them to the project's account, and an admin may add more by hand. Discovery only adds: a region is removed by an admin. A resource in a region the project had never used appears after the next discovery, which runs daily and once when the project is verified, rather than at the next collection. The subnets Google creates in every region for an auto-mode network, such as default, are not counted as use: a region holding only those is not added, and those subnets are listed on their network rather than as rows of their own.

Module What it does Cadence Google permissions
gcp.discovery.region Finds the regions the project uses, from one names-only listing per regional service, and adds them to the project's regions; stores no resource slow, per project compute.forwardingRules.list, compute.instances.list, compute.networks.list, compute.subnetworks.list, container.clusters.list, run.services.list
perf.gcpmonitoring Performance series of the project's measured resources, every region at once, from Cloud Monitoring's time series: values only, aggregated per resource, one read of a metric for up to a hundred resources metrics (hourly), per project monitoring.timeSeries.list

The Google Cloud billing export

Spend reads a Google Cloud billing account's detailed usage cost export, the table gcp_billing_export_resource_v1_<billing account> that Google writes into a BigQuery dataset the customer chooses. The export is enabled in the Cloud console's Billing export page by someone holding Billing Account Administrator or Billing Account Costs Manager; Google has no API for that step. A dataset in the EU or US multi-region is backfilled from the start of the previous month.

The read is not made under the reader's custom role, which stays metadata only. The project holding the export is connected like any other project, and its reader is bound two predefined roles beside that role:

Role Where Why
roles/bigquery.jobUser the project holding the export to run the query (bigquery.jobs.create)
roles/bigquery.dataViewer the export's dataset alone, never the project to read the export's rows (bigquery.tables.getData); the dataset should hold the export and nothing else

The job cost.gcp_billing runs daily for every Google project. The project holding an export runs one query a month for the current month and the two before it, through BigQuery's jobs.query and jobs.getQueryResults. Each query is capped by maximumBytesBilled (10 GiB unless the export's configuration says otherwise), filtered on the export's partitions from the month's start to the moment of the pull, and paged. A query over the cap is refused whole by BigQuery, bills nothing and writes nothing; the run says to raise the cap. A reader without the two roles is refused the same way, and the run names them. The export's conversion rate is never read: each currency stays apart. Corrections Google appends up to two months after their usage are read by a later pull; older months keep what the last pull that reached them wrote.

An administrator configures each export on Spend's Settings page (or POST /cost/gcp-billing-exports): the billing account, the table as project.dataset.table, and the byte cap. Changing or removing one asks for the password again; each write is in the audit log. The page shows each export's last read — the latest run of cost.gcp_billing for the table's project, with the reason when it was refused. Removing an export stops its reads; what was read stays.

The Azure reader

deploy/azure/reader-role.json, a custom role in each connected Azure subscription, assigned at the subscription to the app registration the platform signs in as (deploy/azure/reader.bicep). The platform signs in by outbound identity federation from its own AWS identity, or with a certificate on a deployment off AWS; no client secret exists. The role grants exactly the actions below, no wildcard and no data action. The built-in Reader would not do: its */read reads a site's configuration and Key Vault's secrets' names. Verification also reads the subscription (Microsoft.Resources/subscriptions/read) and the app's own permissions there (Microsoft.Authorization/permissions/read), and fails a role that grants any action besides these.

Every Azure module runs once per subscription: an Azure resource's id names no location, so its region is a property the region filter reads, as a Cloud SQL instance's is. Each list is paged to its end, and a list that Azure throttles past its retries is incomplete, not empty.

Module Resource Tier Azure actions
azure.compute.virtualmachine Virtual machines and their power state; never their user data and no command standard Microsoft.Compute/virtualMachines/read, Microsoft.Compute/virtualMachines/instanceView/read
azure.containerservice.managedcluster AKS clusters and their node pools; never their credentials standard Microsoft.ContainerService/managedClusters/read
azure.sql.database SQL databases, server by server, each server's master left out standard Microsoft.Sql/servers/read, Microsoft.Sql/servers/databases/read
azure.postgresql.flexibleserver PostgreSQL flexible servers standard Microsoft.DBforPostgreSQL/flexibleServers/read
azure.storage.account Storage accounts and their availability; never their keys or a shared access signature standard Microsoft.Storage/storageAccounts/read
azure.network.virtualnetwork Virtual networks, their subnets and peerings standard Microsoft.Network/virtualNetworks/read
azure.web.site App Service apps, web apps and function apps; never their app settings or connection strings standard Microsoft.Web/sites/read

No action here returns content. A storage account's keys, a cluster's credentials and a site's app settings come from other actions (listKeys, listClusterAdminCredential, config/list), which the role never grants and verification refuses to see granted. The sites' list returns no settings; an answer that carried them would be refused whole and nothing of it stored.

One job that is not a collector reads the subscription too, and the role holds its one action:

Module What it does Cadence Azure actions
perf.azuremonitor Performance series of the subscription's measured resources — virtual machines, PostgreSQL flexible servers, SQL databases, storage accounts (with their blob service's count), App Service apps and AKS clusters — from Azure Monitor's platform metrics: numbers about each resource, one read per resource for every metric it has, a storage account's transactions read again split by response type; a resource deleted since the inventory read it is skipped; a statistic Azure refuses for one metric drops that series alone, and a resource Azure Monitor has no metric configuration for drops that resource for the run, each named on the run; nothing is kept from before a resource was made where Azure gives its creation time (virtual machines, SQL databases, storage accounts, PostgreSQL flexible servers), and for App Service apps and AKS clusters, which it gives none, nothing on a subscription's first read before the first sign of the resource's life metrics (hourly), per subscription Microsoft.Insights/metrics/read

A role that predates it fails verification's scope check, naming the action, and its runs are reported, not failed, until the role is updated from deploy/azure/reader-role.json.

The Azure export reader

Spend reads an Azure subscription's spend from the customer's own Cost Management export (FOCUS, daily, to a storage container) — or from the ActualCost and AmortizedCost exports of the same scope, both in that container — never from the Cost Management APIs. deploy/azure/export-reader-role.json is a second custom role, assigned to the same app on that one container (deploy/azure/export-reader.bicep), never the storage account or wider. It holds one data action and no action:

Data action What it reads
Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read the list of the export's blobs and their bodies

An administrator configures each export on Spend's Settings page (or POST /cost/azure-billing-exports): the subscription whose reader reads it, the storage account, the container, the export's directory — and, for the ActualCost and AmortizedCost pair, the second export's directory — and the most one file may hold. Changing or removing one asks for the password again; each write is in the audit log. The page shows each export's last read — the latest run of cost.azure_billing for its subscription, with the reason when it was refused. Removing an export stops its reads; what was read stays.

The platform asks for a Storage token for this read alone and sends it to the Blob service and nowhere else. It never writes or deletes a blob, never reads the account's keys and never asks for a user delegation key. The reader role above keeps no data action.

The report role

deploy/cloudformation/cost-report-role.yaml is deployed only in an account that delivers a Cost & Usage Report, and only for the bucket and prefix that account names. It is the one role that reads object contents: the report's own files, which hold the account's billing line items.

Statement IAM action Scope
ListReportPrefix s3:ListBucket the report bucket, and only keys under the report prefix
ReadReportObjects s3:GetObject objects under the report prefix, and nothing else in the bucket

It has no bucket-wide read and no wildcard resource. A bucket encrypted with a customer-managed KMS key also needs a decrypt grant on that key, which the account adds to its own copy. Its trust policy is the reader role's: the external id (sts:AssumeRole), the source identity (sts:SetSourceIdentity) and the session tags (sts:TagSession).

The jobs that are not collectors

Module What it does Cadence Access
cost.ce_aggregate, cost.ce_resource, cost.ce_backfill Cost Explorer ingestion and its backfill daily, per account the reader role
cost.cur The Cost & Usage Report pull daily, per account the report role
cost.gcp_billing Google Cloud's billing export pull, from BigQuery daily, per Google project the project's reader service account, with the two roles above
cost.trusted_advisor Trusted Advisor recommendations daily, per account the reader role
cost.kubernetes Kubernetes attribution daily, per account none of its own: the inventory and the report's line items
cost.detect_anomalies, cost.evaluate_budgets Anomalies and budgets daily, per tenant none: the stored rollups
cost.forecast The month-end forecast, per tenant, team and account daily, per tenant none: the stored rollups
cost.verify_savings Measures every savings claim again and keeps a new version of its verdict when the answer changed daily, per tenant none: the stored per-resource cost rows
perf.cloudwatch Performance series metrics (hourly), per account and region the reader role
perf.cloudwatch.global Performance series of the resources with a global identity (CloudFront), read in us-east-1 metrics (hourly), per account the reader role
perf.gcpmonitoring Performance series of a Google Cloud project, from Cloud Monitoring metrics (hourly), per project the project's reader service account
perf.azuremonitor Performance series of an Azure subscription, from Azure Monitor metrics (hourly), per subscription the reader app
aws.ec2.lifecycle The EC2 instances that start and stop between two reads: EC2's state-change events, from the queue the reader-role stack creates in each region standard, per account and region the reader role, on that queue alone
aws.cloudtrail.attribution Who made a configuration change: CloudTrail's events for the resource between its two observations on demand: when a change to a resource in an account with CloudTrail attribution on is 15 minutes old, per account and region, never on a schedule the reader role

Versions

What Version
PostgreSQL 16
Kubernetes tested on 1.37 (kind v0.33.0, 2026-09-12). The manifests need 1.21 or later (policy/v1 disruption budgets). KEDA and External Secrets are optional components
The agent 0.3.47, with OpenTofu 1.12.9 and the Library's first thirty-seven releases in its image. The platform admits agents from 0.2.0 (minAgentVersion); an agent runs the first release's templates from 0.2.1, the second's from 0.3.1, the third's from 0.3.2, the fourth's from 0.3.3, the fifth's from 0.3.4, the sixth's from 0.3.5, the seventh's from 0.3.6, the eighth's from 0.3.7, the ninth's from 0.3.8, the tenth's from 0.3.9, the eleventh's from 0.3.10, the twelfth's from 0.3.11, the thirteenth's from 0.3.12, the fourteenth's from 0.3.13, the fifteenth's from 0.3.14, the sixteenth's from 0.3.15, the seventeenth's from 0.3.16, the eighteenth's from 0.3.17, the nineteenth's from 0.3.18, the twentieth's from 0.3.19, the twenty-first's from 0.3.20, the twenty-second's from 0.3.21, the twenty-third's from 0.3.22, the twenty-fourth's from 0.3.24, the twenty-fifth's from 0.3.25, the twenty-sixth's from 0.3.26, the twenty-seventh's from 0.3.27, the twenty-eighth's from 0.3.36, the twenty-ninth's from 0.3.37, the thirtieth's from 0.3.38, the thirty-first's from 0.3.39, the thirty-second's from 0.3.40, the thirty-third's from 0.3.41, the thirty-fourth's from 0.3.42, the thirty-fifth's from 0.3.43, the thirty-sixth's from 0.3.44 and the thirty-seventh's from 0.3.45
Built with Go 1.26.10 (every module's go.mod) and Node 24.21.0 for the portal

Generated from platform/docs/capabilities.md (06951eec68c3) by www/tools/docs; the value in brackets is a hash of the source's content, so a page changes only when its source does.